puts("[ ** WELCOME TO ROBO CASINO **]"); puts( " , ,\n" " (\\____/)\n" " (_oo_)\n" " (O)\n" " __||__ \\)\n" " []/______\\[] /\n" " / \\______/ \\/\n" " / /__\\\n" "(\\ /____\\\n" "---------------------"); puts("[*** PLEASE PLACE YOUR BETS ***]"); for ( i = 0; i <= 0x1D; ++i ) { printf("> "); if ( (unsignedint)__isoc99_scanf(" %c", &input) != 1 ) exit(-1); srand(input); if ( rand() != check[i] ) { puts("[ * INCORRECT * ]"); puts("[ *** ACTIVATING SECURITY SYSTEM - PLEASE VACATE *** ]"); exit(-2); } puts("[ * CORRECT *]"); } puts("[ ** HOUSE BALANCE $0 - PLEASE COME BACK LATER ** ]"); return0; }
上面是 ida 反編譯的主程式邏輯,總之我們就是要連續輸入正確的亂數種子來符合 check 陣列裡的值,所以就是一個 flag checker,這裡我們來撰寫 exploit 來算出對應的亂數種子。
Exploit
1 2 3 4 5 6 7 8 9 10 11 12 13
import ctypes libc = ctypes.CDLL('libc.so.6') mapping = {} for i inrange(255): libc.srand(i) mapping[libc.rand()] = chr(i) flag = "" from pwn import * casino = ELF("./casino", checksec=False) for b inrange(30): val = casino.u32(casino.sym["check"] + b * 4) flag += mapping[val] print(flag)
首先我們載入 ctypes 讓 python 可以呼叫 C 標準函式庫中的函數。 然後使用 ctypes.CDLL 函數來加載 Linux 的 C 標準函式庫 libc.so.6,這樣加載後的 libc 物件就可以直接呼叫 C 標準庫中的函數,例如題目中用到的 srand() 和 rand()。 然後我們遞迴 ascii 的範圍建一個字典,再來我們可以透過 ida 觀察到 check 陣列觀察到有 30 個 4 bytes,所以這裡我們可以把 casino 用 pwntools 載進來之後透過 u32 以及一次移動我們的指針四個單位來找到對應的隨機種子,最後印出我們的 flag。
1 2
╰─ file casino ─╯ casino: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=7618b017ef4299337610a90a0a6ccb7f9efc44a4, for GNU/Linux 3.2.0, not stripped