Home Linux Kernel Exploit Development (Part 1/10)
Post
Cancel

Linux Kernel Exploit Development (Part 1/10)

Linux Kernel Exploit Development with VMware - Lab1::Debugging Environment


목차

  1. 목차
  2. Debugging Environment
  3. Debugger Attach
  4. Debug Program

Debugging Environment

우선 디버깅 환경을 살펴보니 MasterVMTestVM(1,2)으로 구성이 되어 있다. MasterVMTestVM을 디버깅하기 위해 필요한 패키지들이 설치되어 있는 VM이고, TestVM은 Debug/Explot 대상이 될 VM이다.

먼저 TestVM1의 .vmx 파일 수정을 통해 VMware debugStub을 활성화시킨다. 아래 내용을 .vmx 파일에 추가한다.

1
2
debugStub.listen.guest64 = "TRUE"
debugStub.listen.guest64.remote = "TRUE"

TestVM1이 64bit VM이기 때문에 *.guest64 옵션으로 설정해준다. (32bit VM을 디버깅하려면 *.guest32 옵션으로 설정해주면 된다.) 이후 해당 VM에서 gdbserver 0.0.0.0:8864 listen 상태가 되기 때문에 해당 VM의 ip와 8864번 포트를 통해 remote debugging이 가능해진다.

이제 아래 값을 .vmx 파일에 추가해 TestVM1에 추가적인 시리얼 포트를 생성한다.

1
2
3
serial1.present = "TRUE"
serial1.fileType = "file"
serial1.fileName = "/tmp/testvm1"

저장 후 TestVM1을 부팅한다.

부팅이 완료되었으면, GRUB config(/boot/grub/grub.cfg)를 수정해야 한다.

Before

1
2
3
4
5
6
7
8
9
10
11
99 menuentry 'Ubuntu, with Linux 3.5.0-23-generic (stock)' --class ubuntu --class gnu-linux --class gnu    --class os {
100         recordfail
101         gfxmode $linux_gfx_mode
102         insmod gzio
103         insmod part_msdos
104         insmod ext2
105         set root='(hd0,msdos1)'
106         search --no-floppy --fs-uuid --set=root cba0f2b2-4d3a-412e-abd0-84f430c8c448
107         linux   /vmlinuz-3.5.0-23-generic root=/dev/mapper/ubuntu-root ro
108         initrd  /initrd.img-3.5.0-23-generic
109 }

After

1
2
3
4
5
6
7
8
9
10
11
12
99 menuentry 'Ubuntu, with Linux 3.5.0-23-generic (stock)' --class ubuntu --class gnu-linux --class gnu    --class os {
100         recordfail
101         gfxmode $linux_gfx_mode
102         insmod gzio
103         insmod part_msdos
104         insmod ext2
105         set root='(hd0,msdos1)'
106         search --no-floppy --fs-uuid --set=root cba0f2b2-4d3a-412e-abd0-84f430c8c448
107         linux   /vmlinuz-3.5.0-23-generic root=/dev/mapper/ubuntu-root ro console=ttyS1,115200n8 nosm
   ep nosmap
108         initrd  /initrd.img-3.5.0-23-generic
109 }

저장 후 VM을 재시작한다. cat /proc/cpuinfo | grep -E 'sm[e|a]p 명령을 통해 smepsmap 옵션이 비활성화 되었는지 확인한다.

Debugger Attach

MasterVM, TestVM의 네트워크를 NAT로 설정한 후 IP Address를 확인한다.

MasterVM: 192.168.94.175 TestVM: 192.168.94.174

이때, Host의 IP는 192.168.94.1이므로, 이 IP로 Attach하면 된다. 이후 MasterVM에서 gdb를 통해 TestVM1에 attach한다.

1
2
3
4
5
6
7
8
[email protected]:~# gdb -q kernels/vmlinux-3.5.0-23-generic
Reading symbols from kernels/vmlinux-3.5.0-23-generic...done.
(gdb) target remote 192.168.94.1:8864
Remote debugging using 192.168.94.1:8864
native_safe_halt () at /build/buildd/linux-lts-quantal-3.5.0/arch/x86/include/asm/irqflags.h:50
warning: Source file is more recent than executable.
50	}
(gdb)

Debug Program

아래 프로그램을 TestVM에서 컴파일한다.

1
2
3
4
5
6
7
#include <stdio.h>

int main() {
        printf("test\n");

        return 0;
}
1
2
3
4
5
6
7
8
test@ubuntu:~/exercises/syscall_bp$ gcc -o trigger trigger.c
test@ubuntu:~/exercises/syscall_bp$ ls
trigger  trigger.c
test@ubuntu:~/exercises/syscall_bp$ file trigger
trigger: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), forGNU/Linux 2.6.24, BuildID[sha1]=0xb765e4c5a119d7f5dbab570bdee3cd30c2cba8c6, not stripped
test@ubuntu:~/exercises/syscall_bp$ ./trigger
test
test@ubuntu:~/exercises/syscall_bp$

이제 해당 프로그램의 printf() 함수 내에서 호출하는 sys_write()함수에 breakpoint를 걸고, 출력 값을 test에서 1337로 변경해 보자.

우선, breakpoint를 sys_write에 걸어야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(gdb) b * sys_write
Breakpoint 1 at 0xffffffff81187e10: file /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c, line 479.
(gdb) c
Continuing.

Breakpoint 1, sys_write (fd=10, buf=0x7f0e8c209640 ".", count=1)
    at /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c:479
warning: Source file is more recent than executable.
479	{
(gdb) c
Continuing.

Breakpoint 1, sys_write (fd=2,
    buf=0x1f2f008 ".]0;[email protected]: ~/exercises/syscall_bp\a[email protected]:~/exercises/syscall_bp$ ", '\337' <repeats 123 times>, <incomplete sequence \337>..., count=1)
    at /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c:479
479	{
(gdb) c
Continuing.

Breakpoint 1, sys_write (fd=3,
    buf=0x7f0e8c1f27c0 "oE\322I\227\002产\347\004h\260\353\272\025\f3\225O=*x\221̴`\233\263\241U]z\250\275\234TF\360\021y\333\327\064H\231\035\320\b@?\367\243\344-\363\321F\a\016e5\025Ѿ\355\262\220\226\363*\366\202V\243\226\371!\276\226Z\003c\203\201J\212\030\311\317G\347\366\001\317\060\262\362q$Ⓨ՛\377Ub\276\177\063\336\371\350\233[\301\177\r\321Mk-\362\t\004]{\213w:\375\365\030j\215pf1\375x\347\022h>\004\367\337P\332\352\212\361'g4\376_sw\177\371\342\201%#\023\035R\362ϧf;\205", count=64)
    at /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c:479
479	{
(gdb)

하지만 위의 출력처럼 fd의 값이 2,3,10 등인 sys_write 함수 호출까지 잡히기 때문에 printf()로 출력되는 문자열(stdout)만 보기 위해 conditional breakpoint를 잡아준다.

1
2
3
4
(gdb) b * sys_write if (fd==1)
Breakpoint 2 at 0xffffffff81187e10: file /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c, line 479.
(gdb) c
Continuing.

이후 ./trigger 명령을 통해 breakpoint가 printf 지점에 정확하게 잡히는지 확인해본다.

testVM

1
test@ubuntu:~/exercises/syscall_bp$ ./trigger

MasterVM

1
2
3
4
5
6
7
(gdb) c
Continuing.

Breakpoint 2, sys_write (fd=1, buf=0x7f80d1e5c000 "test\n", count=5)
    at /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c:479
479	{
(gdb)

우리가 찾던 "test\n" 문자열이 정확하게 잡혔다. 이제 rsi 레지스터가 가르키는 주소의 값을 변경하여 1337을 출력하도록 변조해보자.

MasterVM

1
2
3
4
5
6
7
8
9
10
11
(gdb) c
Continuing.

Breakpoint 2, sys_write (fd=1, buf=0x7f1f7e831000 "test\n", count=5)
    at /build/buildd/linux-lts-quantal-3.5.0/fs/read_write.c:479
479	{
(gdb) set {char [6]} 0x7f1f7e831000 = "1337\n"
(gdb) x/s 0x7f1f7e831000
0x7f1f7e831000:	"1337\n"
(gdb) c
Continuing.

TestVM

1
2
3
test@ubuntu:~/exercises/syscall_bp$ ./trigger
1337
test@ubuntu:~/exercises/syscall_bp$

1337을 성공적으로 출력했다. 이제 다음 Lab으로 넘어가자!

This post is licensed under CC BY 4.0 by the author.