本文作者:萌新
前情回顧:
0x08
題目給的提示是和運算符優先級有關
登錄后直接看源碼
mistake@pwnable:~$ ls flag mistake mistake.c password mistake@pwnable:~$ cat mistake.c #include <stdio.h> #include <fcntl.h> #define PW_LEN 10 #define XORKEY 1 void xor(char* s, int len){ int i; for(i=0; i<len; i++){ s[i] ^= XORKEY; } } int main(int argc, char* argv[]){ int fd; if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){ printf("can't open password %d\n", fd); return 0; } printf("do not bruteforce...\n"); sleep(time(0)%20); char pw_buf[PW_LEN+1]; int len; if(!(len=read(fd,pw_buf,PW_LEN) > 0)){ printf("read error\n"); close(fd); return 0; } char pw_buf2[PW_LEN+1]; printf("input password : "); scanf("%10s", pw_buf2); // xor your input xor(pw_buf2, 10); if(!strncmp(pw_buf, pw_buf2, PW_LEN)){ printf("Password OK\n"); system("/bin/cat flag\n"); } else{ printf("Wrong Password\n"); } close(fd); return 0; }
看關鍵:
main調用的xor函數:
將長度給len的字符串與1異或
main中的主要邏輯
從/home/mistake/password讀10個字節數據放到pw_buf,我們手動輸入10字節數據放在pw_buf2,如果pw_buf2與1異或的結果如果與pw_buf相等,則打印flag
那么關鍵就是pw_buf的數據,先直接讀password看看
沒有權限
題目的提示是和運算符優先級有關
我們仔細分析源碼,看看問題出在哪里
問題在這里
if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){
open函數里權限檢查是沒問題的,O_RDONLY表示以只讀方式打開
0400表示文件所有者具有可讀取的權限
由於權限通過檢查,所以open函數返回值為0
有因為0<0不成立
所有比較結果為0
然后賦值給fd
即fd為0,表示標准輸入,也就是說fd現在是我們可控的
結合之前分析,pw_buf也為我們控制
那就很簡單了
第一次輸入10個1,存入pw_buf
第二次輸入10個0,存入pw_buf2,與1異或后覆蓋pw_buf2,此時buf2的值也為10個1,滿足打印flag的邏輯
0x09shellshock
查看權限
可以看到shellshock程序的所屬組的權限位上有s,表示sgid,也就是說在執行shellshock時,用戶將獲得shellshcok所屬組的權限,即執行shellshock后將獲得root所在用戶組的權限,而由flag這一行的權限位可知,該權限可以讀取flag
這一點從源碼中也可以看出來
getegid()返回進程執行有效組識別碼。在這里getegid()返回的就是root所在用戶組的id
setresuid用於設置ruid,euid,seuid,在這里就是統統都設置為進程當前的egid
setresgid用於設置rgid,egid,sgid,這里也是統統設置為進程當前的egid
因為s標志,所以egid實際上是root所在用戶組的id
再根據題目提示的shellshock
這是著名的bash破殼漏洞
直接在網上找到poc修改下即可
解釋一下發生了什么
首先在當前環境下定義了X函數,函數體由{}括起來,然后在函數體外加了一條額外的語句/bin/cat ./flag即打印flag的命令,這條語句會在后面執行./shellshock時被調用,由於執行shellshock時會有root權限,所以自然就有權限來打印flag了
想知道怎么操作嗎?點擊開始實踐——破殼漏洞實踐:http://www.hetianlab.com/expc.do?ec=ECID172.19.105.222014092915250400001
0x10
按照要求連接服務器
這是一個小游戲
大意是一堆貨幣里有真幣假幣,兩者重量不同,真幣10g,假幣9g。給你N個硬幣,C次機會,讓你猜哪一個是假幣。需要在30s的時間里才對100次。
這題其實考的是算法。
分治法解決
舉個例子。
一共100個硬幣,其中1個是假的,先稱重1-49,如果結果整除10,則假幣在50-100.
第二輪稱50-75,如果不整除10,則假幣在其中
第三輪稱50-62.。。。。
其實就是簡單的二分法
編程
import time from pwn import * conn = remote('0', 9007) conn.recv(10000) for _ in range(100)://猜100次 line = conn.recv(1024).decode('UTF-8').strip().split(' ') print(line) n = int(line[0].split('=')[1])//讀出給的n,c c = int(line[1].split('=')[1]) left = 0 right = n//共n個硬幣 for _ in range(c)://二分法猜解 guess = ' '.join(str(left) for left in range(left, int((left+right)/2))) conn.sendline(guess)//給出需要猜測的貨幣 output = int(conn.recv(1024).decode('UTF-8').strip())//讀取返回稱重的結果 if (output % 10 == 0)://整除10的情況 left = int((left+right)/2) else://不整除的情況 right = int((left+right)/ 2) conn.sendline(str(left)) print(conn.recv(1024).decode('UTF-8'))//打印一輪的結果 print(conn.recv(1024).decode('UTF-8')) conn.close()
以上一關的shellshock登錄服務器,在tmp目錄下新建一個python 腳本
按照提示
用pwntools編寫的時候,注意remote(‘0’,9007)
執行如下
0x11 blackjack
em...源碼有點長,直接看關鍵部分
這里會校驗我們輸入的金額
如果比cash大則會報錯,並要求再次輸入
不過再次輸入的時候不會報錯了
考慮到要賺夠1000000,而輸的幾率比較大
我們可以輸入-的金額,比如-1000000,只要輸了就可以拿到flag
然后選擇y就打印出flag了