티스토리 뷰
이번에 OSTeam으로 참여했던 NuitDoHack에서 리눅스 바이너리 문제를 풀던 나는 흥미로운 ELF Binary를 발견했었다. 이번 포스팅에서는 그 문제에 포함되어 있던 Anti 기법에 대해 적어보려 한다.
※ 이 글은 문제풀이에 중점을 두는게 아닌 분석가를 힘들게 하는 ELF Anti Trick 에 중점을 둔다.
------------------------------------------------
문제 정보
Clark - Binary 150
Clark Kent
"There's a shadow inside all of us.
But that doesn't mean you need to embrace it.
You decide who you really are.
And I know you'll make the right choice
and become the hero you're destined to be."
(Clark Kent)
Become that hero you're destined to be.
Discover and evolve your reversing powers.
------------------------------------------------
1. 정보 수집
안티를 분석하기 전 파일의 정보를 확인해보자.
#file clark
clark: ELF 32-bit LSB executable, Intel 80386, invalid version (SYSV), for GNU/Linux 2.6.24, dynamically linked (uses shared libs), corrupted section header size
file 명령을 통해 확인해 보면 섹션헤더 사이즈가 올바르지 않다고 출력된다.
kino@ubuntu:~$ ./clark
Welcome to NDH2k15
Need supercow power!!!
Bye!
실행해보면 정상적으로 실행된다.
gdb 로 실행해 보자.
kino@ubuntu:~$ gdb -q ./clark
"/home/kino/clark": not in executable format: File truncated
(gdb) r
Starting program:
No executable file specified.
Use the "file" or "exec-file" command.
파일의 포맷이 맞지 않아 정상적으로 gdb를 통해 실행되지 않는다고 출력된다.
2. 헤더 검증
readelf 명령을 통해 헤더를 확인해 보자
-----------------------------------------------------------
kino@ubuntu:~$ readelf -h ./clark
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x0
Entry point address: 0x80483e0
Start of program headers: 52 (bytes into file)
Start of section headers: 123 (bytes into file)
Flags: 0x0
Size of this header: 0 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 9
Size of section headers: 0 (bytes)
Number of section headers: 0
Section header string table index: 0
readelf: Warning: possibly corrupt ELF file header - it has a non-zero section header offset, but no section headers
-----------------------------------------------------------
출력된 결과로 이상한 부분들을 하나하나 짚어보자.
- Size Of This Header : 0
Size Of This Header는 현재 출력된 ELF Header의 크기이다. 모든 ELF 프로그램들이 ELF헤더를 포함하고 있으며 이 크기는 32bit인 경우 52byte를 가져야 한다.
- Start of section header : 123
- Size of section header : 0
- Number of section header : 0
섹션에 관련된 정보들이 맞지 않다. 헤더에서 섹션헤더의 시작 위치가 명시되어 있지만 사이즈나 섹션의 갯수는 0으로 표기되어있다. 이는 실제 섹션이 존재하지 않지만 시작위치를 명시해 주었거나(섹션이 존재하지 않아도 실행 가능하다. 링킹 단계를 거친 실행 프로그램은 섹션이 아닌 세그먼트 단위로 참조하기 떄문), 123위치에서 섹션이 시작하지만 섹션의 갯수나 사이즈를 0으로 설정했다고 볼 수 있다.
물론 실제 바이너리를 들여다보며 섹션스러운(?!) 정보를 찾아가며 검증할 수도 있겠지만 위의 정보만으로도 충분히 유추가 가능하다. 세그먼트, 섹션, 헤더 등의 정보들은 짝수 단위로 떨어지게 된다(alignment). 하지만 이 바이너리의 섹션 헤더의 경우 offset 123byte, 즉 홀수로 떨어지는 위치를 가리키고 있으며 이는 offset위치가 잘못되었음을 의미한다.
3. 결론 도출
이 ELF의 헤더는 일부 필드의 값들이 잘못되어 있으므로 헤더 정보만 수정해 주면 정상적으로 GDB등에서 실행 가능할 것이다.
- Size of this header : 0 -> 52 byte
- Start of section header : 123 -> 0
4. TEST!!
되겠지뭐...
수정전 :
-----------------------------------------------------------------------
00000000 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 ELF
00000010 02 00 03 00 00 00 00 00 E0 83 04 08 34 00 00 00 ? 4
00000020 7B 00 00 00 00 00 00 00 00 00 20 00 09 00 00 00 {
00000030 00 00 00 00 06 00 00 00 34 00 00 00 34 80 04 08 4 4
-----------------------------------------------------------------------
수정후 :
-----------------------------------------------------------------------
00000000 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 ELF
00000010 02 00 03 00 00 00 00 00 E0 83 04 08 34 00 00 00 ? 4
00000020 00 00 00 00 00 00 00 00 34 00 20 00 09 00 00 00 {
00000030 00 00 00 00 06 00 00 00 34 00 00 00 34 80 04 08 4 4
-----------------------------------------------------------------------
실행결과
kino@ubuntu:~$ gdb -q ./clark_fixed
Reading symbols from /home/kino/clark_fixed...
warning: no loadable sections found in added symbol-file /home/kino/clark_fixed
(no debugging symbols found)...done.
(gdb) r
Starting program: /home/kino/clark_fixed
Booh! Don't debug me!
[Inferior 1 (process 8301) exited with code 01]
4. 결론
또다른 안티 디버깅에 걸리긴 하지만.. 어찌되었건 원하던 목표인 gdb에 붙였다.
사실 이러한 방법자체가 아주 신선하거나 새로운 방식은 아니지만(검색중에 알았는데 이미 이전부터 나와있던 방법이었음. 걍 내가 나태한거임) 처음 겪은 내입장에선 꽤나 신선했다.
음.. 어떻게 마무리를 못하겠다.
뿅!
PS : 이 문제에는 이거말고도 다른 안티들이 있긴한데.. 이건 헤더쪽이 아닌 코드상에서의 안티인데다가 악성코드를 주제로 포스팅 할때 함께 다루든지 해야지..