제 1회 UNIST 알고리즘 프로그래밍 경진대회 Uni-CODE 가 성공적으로 마무리되었습니다!! 총 19분이 신청해주셨고, 최종적으로 14분이 참가해주셨습니다. 1위는 전기전자컴퓨터공학부의 ‘한동규’님입니다. 다음 대회도 여러분들의 많은 참여바랍니다. 또한, 문제 및 풀이, 스코어보드가 공개되었습니다.
안녕하세요, 이번 HeXA CTF 2016 운영 총괄을 맡은 HeXA 회장 겸 해킹부장 김동민(SleepyBear)입니다. 아무것도 모르고 Layer7 CTF와 Holyshield CTF에 참여했던 고등학생 때가 엊그제같은데 직접 CTF를 운영하게 되었네요.
UNIST 교내 학생만들을 대상으로 하는, CTFTime이나 국내 고등학교, 대학교 동아리 개최 CTF들에 비해서는 작은 규모였지만 제게는 문제를 푸는 입장을 넘어서 지금까지 공부한 것을 토대로 출제진과 함께 문제를 만들어 제공하는 기회가 되어 의미있었던 것 같습니다.
플랫폼
이번 CTF에서는 페이스북에서 제공한 오픈소스 CTF 플랫폼을 사용해보았습니다. 실시간 스코어보드 및 그래프, King of the Hill(거점점령)문제 지원, Quiz 지원(대소문자를 구별하지 않는 단답형 flag), 문제별 Breakthru 지정, Admin Dashboard 기능이 마음에 들어서였습니다.
하지만 대회 당일에 웹사이트 속도가 급격히 느려져서 대회 기간동안 진땀뺐습니다… 테스트때는 스탭들만 접속해봐서 느려진다는걸 전혀 못느꼈거든요. 서버 CPU 점유율이 점점 올라가길래 재부팅도 해보고, hhvm 퍼포먼스 관련 이슈도 해결해보겠다고 조마조마하면서 라이브 패치도 하고… 중간에 플랫폼을 옮길까 생각도 해보았지만 결국 점수 관리때문에 문제만 따로 모아둔 Google Docs를 제공할 뿐이었습니다.
이 밖에도 준비하는 과정에서 회원가입 시 입력한 이메일이 DB에 저장되지 않는다던가, 스코어보드 그래프가 일정 시간 이후가 표시되지 않는다던가 하는 잔버그들이 너무 많았습니다. OTL. 다음에는 HeXA CTF 2015때 이용했던 플랫폼에 이번에 마음에 들었던 기능들을 추가해서 사용할 것 같습니다.
문제
저를 포함한 6명이 총 33문제를 만들었습니다. 저는 포렌식 문제를 좋아해서 포렌식 위주로 문제를 내보았습니다. 포렌식 문제에 주어진 자료를 분석하는 것과 자료를 만드는 것은 전혀 다른 경험이더라구요. 랜섬웨어에 감염되어볼까도 생각해보고, VM 이미지를 어떻게 하면 깔끔하게 만들어 제공할 수 있을까 한참 고민해보기도 했습니다. 결국 이번에 저는 기술적인 문제보다는 트릭을 이용한 문제를 많이 만들었습니다.
가상의 인물을 만들어 신상을 털게 해볼까 하는 아이디어에서 출발한 ‘레스토랑스의 습격’ 문제와 지하철 노선도를 이용한 뿌링클 기프티콘 이벤트문제도 dohan0930이 만들었어요. 재미있는 경험이었고 앞으로 제가 경험한 다양한 사례들을 문제에 녹여낼 수 있게 부지런히 공부해야겠다고 다짐했습니다.
마무리
이번에 출제된 문제를 바탕으로 HeXA 멤버들을 위한 워게임 사이트를 만들 계획을 하고있습니다. 이런 문화를 만들어주신 선배님들께 감사하고, CTF에 참여해주신 분들도 모두 감사합니다!
First, I think many people know that a html file uploaded on dropbox shows with rendering, and without any escaping. It means that, if we write down a JavaScript code to the html file, we can easily execute a JavaScript code on the html page without any problem. But, the script is executed on a sandbox domain, dl-web.dropbox.com. The important session is a httponly cookie, so we can’t easily steal the user session.
In this situation, I can set any cookie on dropbox.com domain (not www.dropbox.com). It means that it may be able to influence on www.dropbox.com. If main dropbox page do something using the cookie on dropbox.com, then maybe I can do something on www.dropbox.com
Vulnerability
I found a some nice thing, Flash. After cookies, “flash” and “bang”, are given, dropbox page draws a pop-up box which is containing a text in “flash”. But, “bang” was a problem. It seems like a hmac of “flash”. So, I need to find “bang” value of my custom “flash”.
I also found a function which unlinks device in security setting page. If I unlink a some device, then it shows me a flash message, which is containing device name. So, I set the device name (iphone name) to a XSS text, and I unlinked it.
Exploit
Now, I can set “flash” and “bang” value to any text.
Then, set the malicious cookie in a html. After that, make victim to move page to www.dropbox.com (trigger flash message).
문제가 나오고 정말빨리 풀렸는데, 저는 처음에 문제 제목에 현혹되어 shellshock인줄 알고 헤메느라 시간이 많이 걸렸네요… ㅠㅠ 실제로 당황스럽게도 대회 서버에서 CVE-2014-6277이 먹혔더라죠… ;;
하지만 차분히 생각해보면 shellshock는 setuid가 걸려있는 바이너리안에서 bash를 호출해야한다는 점과 환경변수를 필요로 한다는점을 생각해보면 이 문제에서는 shellshock를 사용할 수 없다는걸 바로 알 수 있습니다.
이걸 생각못해서 날린 시간이 몇시간인지.. 흙흙
여튼, 이 문제는 shellshock를 이용해서 푸는 문제가 아닌 strcat을 이용한 단순한 오버플로우 문제입니다. 제대로 된 풀이만 바로 떠올리면 정말 빨리 풀 수 있는 문제이지요… 실제로 문제가 나오자마자 엄청 빠른 속도로 풀린 문제이기도 합니다.
그럼 각설하고 풀이로 들어가보도록 하겠습니다!
문제환경
오호 정확히 strlen의 인자로 넣어준 A들이 들어간것을 볼 수 있습니다.
그럼 이제 해야할것은 argv[1]의 포인터를 덮어씌우기 위해 앞에 몇개의 A를 넣어줘야하는지와 어떤 값으로 덮어써야할지를 정하면 되겠습니다.
어떤값으로 덮어써야할지는 비어있는 문자열 즉 null이 들어있는 주소로 덮어주면 됩니다. 그러면 strlen의 리턴값이 0이 되고, 입력값 검사를 우회할수 있게 됩니다. 그런데 여기서 또 생각해 줘야할 부분이 서버에는 ASLR이 걸려있어 주소들이 랜덤이고 32비트가 아니라 ulimit -s unlimited 같은 꼼수도 못부립니다 ㅠㅠ.. 하지만! 64비트에도 고정인 주소가 있으니… 바로 그부분은 vsyscall 영역입니다.
부분은 ASLR이 걸려있더라도 고정인 주소로 매핑됩니다. 그렇다면 이 vsyscall 영역에 null이 들어있는 주소가있다면?! 그 주소로 strlen의 인자, 즉 argv[1]의 포인터를 덮어씌우면 끝나게 됩니다.
그러면 이제 이 vsyscall 영역에 null문자열이 있는지 한번 찾아봅시다.
찾는방법은 여러가지 있겠으나 저는 peda의 searchmem 기능을 이용하여 찾았습니다. vsyscall 영역에서 null(0x00) 으로 찾으니 꽤 많이 나오는데 이 중에서 값의 중간에 0x00 널값이 포함안되는 값으로 아무거나 하나 정해주면됩니다.
null이 들어가면 안되는 이유는 문제 바이너리를 실행할때 인풋을 argv[1]로 넘겨주는데 이 argv[1]은 중간에 null값이 들어갈 수 없기 때문입니다. ( null 값이 들어가면 null뒤의 값들은 짤립니다.. ㅠㅠ )
여튼 그럼 저는 적당히 0xffffffffff600405 로 골라서 하도록 하겠습니다.
이제 남은일은 앞에 더미값인 A를 몇개나 입력해줘야하는가 인데, 자세히 분석해서 알아낼 수도 있겠지만 대회 특성상 문제를 빨리풀어야하는걸 고려해서 peda의 pattern 명령어를 사용하여 자세히 분석하지 않고도 쉽게 알아낼수 있는 방법을 쓰도록 하겠습니다.
pattern create 1024 pattern.txt 를 입력하면 pattern.txt 라는 파일에 1024개의 패턴 문자가 쓰여지게 됩니다. 그리고 실행할때 r cat pattern.txt 로 실행을 하면 방금 만든 pattern 값들을 argv[1]로 넘기면서 실행할 수 있습니다.
이렇게 실행을 하면,
이렇게 strlen의 인자가 패턴값으로 덮힌것을 알 수 있습니다.
이상태에서 pattern.txt 파일을 열어 ANsA8sAi 의 문자열을 찾아 ( 리틀엔디안이므로 문자열을 뒤집은 것입니다. ) 이 문자열앞의 문자 갯수를 python len 함수같은것을 이용하여 세어봐도 되고, peda의 pattern search 라는 기능을 이용해도 됩니다.
pattern search를 해보면 offset이 525로 나오는데 이게 우리가 구할 offset과 일치합니다.
이렇게 offset을 구했으니 “A” 525개 + “B” 8개 를 넣어서 offset이 맞는지 한번 확인해보도록 하겠습니다.
strlen에 breakpoint를 걸은후, perl -e'print"A"x525, "B"x8' 로 실행시키면 정확히 strlen의 인자로 BBBBBBBB가 들어가는것을 볼 수 있습니다.
그럼 이제 BBBBBBBB 부분 대신에 아까 구해준 null이 들어있는 주소, 0xffffffffff600405 으로 대신 넣어주고 “A”525개에 A만 넣는게 아니라 실행시킬 명령어도 포함시켜 주면 입력값 검사를 안받게되고 임의의 명령어를 실행시킬수 있게 됩니다.
Exploit Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# exploit.py # ./shock "`cat payload`" from struct import pack
이번 포스팅에서는 PEDA에는 어떤 기능들이 있는지, 실제로 어떤식으로 활용할 수 있는지에 대해 살펴보도록 하겠습니다.
PEDA 기본 인터페이스
우선 PEDA의 기본적인 화면은 위와 같습니다.
display 같은 걸 해주지 않으면 기본적으로 화면에 아무것도 안 나오는 gdb와 달리 PEDA는 기본적으로 현재 레지스터의 상태와 실행 중인 명령어와 그 주변 명령어들, 스택의 내용물 등을 표시해줍니다.
특히나 정말 멋진 기능 중 하나는 포인터를 따라가서 그 내용물까지 보여주는 기능입니다. 위 그림에서 레지스터 부분이나 스택 부분을 보면 포인터를 따라가서 그 안의 내용까지 보여주는 걸 볼 수 있습니다. PEDA 짱짱맨!!
그러면 이제 PEDA의 다양한 기능들을 하나씩 하나씩 들여다보겠습니다.
pdisas
pdisas는 gdb에서 쓰던 disas 명령어의 확장판입니다.
위 그림을 보면 알 수 있듯이 pdisas를 사용하면 알록달록한! 컬러풀한! 가독성이 더 높아진 버전의 disas 결과물을 볼 수 있습니다. PEDA는 gdb의 확장이므로 물론 원래 gdb의 기능들도 모두 사용 가능합니다. 그래서 pdisas 와 disas를 위 그림처럼 비교해보면 확실히 pdisas가 컬러링이 잘 돼있어 가독성이 높은 걸 알 수 있습니다.
How to use
1
gdb-peda$ pdisas "Function Name"
Example
1
gdb-peda$ pdisas main
context code / register / stack
context 명령어는 별다른 기능이 아니라 맨 처음에 보여드렸던 PEDA 기본인터페이스 에서 code영역 register영역 stack영역을 따로 따로 볼 수 있는 기능입니다.
How to use
1
gdb-peda$ context "code/register/stack/all" ( context 만 입력시엔 context all 과 같습니다. )
Example
1 2 3
gdb-peda$ context gdb-peda$ context code gdb-peda$ context all
session save / restore
session 명령어! 정말 편리한 기능을 제공하는 명령어입니다. 기존 gdb에서는 열심히 분석하면서 break point도 걸어놓고 watch point도 걸어놓고 해 놓더라도 gdb를 껐다 다시 키면 전부 없어지는데 peda에서는 session이라는 명령어로 break point와 같은 설정들을 저장하고 불러오는게 가능합니다.
위 그림에서도 맨 처음에 info b 를 했을때, “No breakpoints or watchpoints” 가 나오는데 session restore 명령어를 치고 난 후 info b 를 해보면 저장해 놓았던 설정들을 그대로 가져오는 것을 볼 수 있습니다.
How to use
1 2
gdb-peda$ session save "파일이름" ( 파일이름 생략시엔 peda-session-"실행파일이름".txt 로 저장 ) gdb-peda$ session restore "파일이름" ( 파일이름 생략시엔 peda-session-"실행파일이름".txt 로드 )
Example
1 2 3 4
gdb-peda$ session save gdb-peda$ session restore gdb-peda$ session save MySession gdb-peda$ session restore MySession
snapshot save / restore
이것도 상당히 재밌는 기능인데, session 이 break point나 watch point 들을 저장하고 불러온다면 이 명령어는 아예 현재 디버깅중인 프로세스의 스냅샷을 찍어 저장하고 불러올수있게 합니다. 사용법은 session과 동일합니다.
vmmap
이 명령어는 현재 디버깅 중인 프로세스의 Virtual Memory MAP을 보여줍니다. 그냥 vmmap 만 입력할 시에는 vmmap all 과 같으며 위 그림과 같이 vmmap binary, vmmap stack 이런 식으로 특정 메모리 영역만 볼 수도 있습니다.
원래 gdb로 했었더라면 현재 프로세스의 pid를 알아내고 shell cat /proc/“pid”/maps 를 해서 봐야 했을 텐데 PEDA를 사용하면 아주 간단하게 메모리 매핑 상태를 보는 게 가능합니다.
여기서 추가적으로 더 나아가서 얘기하자면, vmmap stack을 사용해서 현재 stack의 권한을 보고 해당 바이너리가 NX가 걸렸는지 안 걸렸는지도 알 수 있습니다.
How to use
1
gdb-peda$ vmmap "all/binary/libc/stack/ld ..." ( 인자를 생략할 시에는 vmmap all 과 같습니다. )
이 명령어는 현재 바이너리에 걸려있는 보안 기법들을 보여줍니다. 사용법은 간단히 그냥 checksec을 입력하기만 하면됩니다. 근데 여기서 주의해야 할 게 다른 건 몰라도 여기서 표시되는 NX는 별로 신뢰하지 않는 게 좋습니다. 버그가 있는지는 몰라도 NX가 안 걸려있는데 걸려있다고 나온다던가… 이런 경우가 몇 번 있어서 통수 맞은 적이 있네요 ㅠㅠ
그래서 밑에서 소개할 nxtest 라는 명령어 또는 vmmap stack과 같은 명령어로 다른방법을 사용해서 NX는 따로 체크해주시는게 좋을 것 같습니다.
How to use
1
gdb-peda$ checksec
nxtest
nxtest는 말그대로 NX 가 걸려있는지 테스트 해주는 명령어로 스택에 실행권한이 있는지 체크합니다.
How to use
1
gdb-peda$ nxtest
procinfo / getpid
procinfo 는 현재 디버깅중인 프로세스의 정보를 위 그림과 같이 표시해 줍니다. pid만 필요하다면 getpid 명령어를 사용하는걸로 pid만 얻을수도 있습니다.
How to use
1 2
gdb-peda$ procinfo gdb-peda$ getpid
elfsymbol
이게 또 참 편리한 기능인데, elfsymbol이라는 명령어로 현재 디버깅 중인 바이너리의 plt 주소, got 주소 등을 알 수 있습니다. exploit 코드를 작성할 때 got overwrite을 한다거나 got 주소를 leak 시켜온다거나 여러 가지의 상황에서 plt 주소와 got 주소가 필요한 경우가 종종 있는데 이럴때 elfsymbol 명령어를 이용하면 아주 쉽게 정보를 얻을 수 있습니다.
How to use
1
gdb-peda$ elfsymbol "symbol" ( 인자를 생략하면 symbol들을 모두 보여줍니다. )
Example
1 2
gdb-peda$ elfsymbol gdb-peda$ elfsymbol printf
elfheader
elfheader 명령어는 현재 디버깅 중인 바이너리의 헤더 정보들을 보여줍니다. 이 기능도 exploit 코드를 작성할 때 종종 bss 영역의 주소가 필요하다거나 하는 경우가 있는데 이럴 때 사용하면 유용합니다.
How to use
1
gdb-peda$ elfheader
Example
1 2
gdb-peda$ elfheader gdb-peda$ elfheader .bss
find / searchmem
find와 searchmem 은 동일한 명령어로 아무거나 선호하는 걸로 사용하시면 되며, 이 명령어는 메모리 영역에서 특정 패턴을 찾아줍니다. 다양한 방법으로 응용될 수 있는데, 몇가지 예시를 들자면 위 그림과 같이 /bin/sh 문자열의 주소를 찾는다던가 특정 OPCODE를 메모리에서 찾는다던가 하는게 가능합니다.
How to use
1
gdb-peda$ find/searchmem "pattern""범위" ( 범위부분을 생략하면 binary 영역으로 세팅 됩니다.)
Example
1
gdb-peda$ find /bin/sh libc
ropgadget / ropsearch / dumprop
ropgadget 과 ropsearch 명령어는 ROP를 할 때 필요한 가젯들을 쉽게 찾을 수 있도록 도와주는 명령어입니다. ropgadget은 자주 쓰이는 가젯들인 pop-ret, leave-ret, add esp 와 같은 가젯들을 찾아줍니다. 또한 ropsearch는 원하는 특정 가젯을 찾을 수 있도록 도와줍니다.
dumprop도 비슷한 명령어인데, 이 명령어는 특정 가젯을 찾기 보다 특정 메모리 영역에서 모든 가젯들을 보고 싶을 때 유용합니다. 하지만 ropsearch ‘’ binary 이런 식으로 사용하면 ropsearch 로도 dumprop와 비슷하게 사용할 수 있습니다.
How to use
1 2 3
gdb-peda$ ropgadget binary/libc/vdso/all ... ( 인자를 생략하면 ropgadget binary 와 같습니다. ) gdb-peda$ ropsearch "gadget""범위" ( gadget 부분을 '' 로 빈 상태로 보내면 모든 가젯을 찾습니다. ) gdb-peda$ dumprop "범위" ( 인자를 생략하면 dumprop binary 와 같습니다. )
이 명령어도 ROP 할 때 유용한 가젯들을 찾아주는데, 그중 jmp와 call 가젯들을 전부 찾아줍니다. 그냥 jmpcall 만 입력하면 바이너리 영역 내의 모든 jmp, call 가젯들을 찾아주며 jmpcall esp libc 처럼 특정 메모리 영역 내의 특정 jmp, call 가젯들만 찾을 수도 있습니다.
How to use
1
gdb-peda$ jmpcall "register""범위" (인자들을 모두 생략하면 jmpcall "" binary 와 같으며, 바이너리 영영 내 모든 jmp, call 가젯들을 찾아줍니다.)
PEDA에는 기본적으로 제공해주는 쉘코드가 몇 가지 있는데 shellcode generate 란 명령어로 현재 가능한 쉘코드 종류를 볼 수 있고, shellcode generate x86/linux exec 이런 식으로 지정하여 필요한 쉘코드를 바로바로 얻을 수도 있습니다.
현재 PEDA에 기본적으로 내장되어 있는 쉘코드는 x86/linux, bsd 뿐이지만 shellcode search나 display로 쉘코드를 웹에서 가져올 수도 있습니다.
Example
1
gdb-peda$ shellcode generate x86/linux exec
이 외에도 PEDA는 많은 기능들을 제공하는데, PEDA에서 제공하는 다른 기능들도 살펴보시고 싶으시면, phelp 또는 peda help 를 입력하셔서 쭉 훑어보시면 됩니다.