안녕하세요. 이번엔 누락된 부분 인 basic rce level 5를 풀어보겠습니다. 홈페이지로 들어가 파일을 받아서 실행해봅시다.

등록키를 알아내는 문제입니다. 올리디버그로 열어봅시다.

PUSHAD로 적혀있는것을 보아 UPX패킹되어있을 확률이 높습니다. EXEINFO PE로 확인해봅시다.

UPX로 패킹되어있군요. UPX패커로 풀어줍시다.

풀었으면 파일을 올리디버그로 열어봅시다. 그리고 아까 보인 실패문구열(WRONG...)을 찾기 위해 오른쪽마우스 - Search for - All referenced text strings를 누릅시다.

문구열을 찾아봅시다.

찾았습니다. 들어가봅시다.

코드를 실행해보니 저기 JMZ가 분기점인 모양입니다. ZF가 0이면 점프를 하여 실패문구열로 가버리는 놈입니다. 그런데 ZF를 결정하는 비교문이 없습니다. 아무래도 바로 위 코드에서 호출하는 부분에 있는 모양입니다. 브레이크를 걸고 실행해봅시다. 등록키값은 그냥 12345로 줍시다.

브레이크에 걸리면 F7키를 이용해 따라가 봅시다.

EAX와 EDX를 비교해서 같으면 JE를 이용해 점프를 합니다. 점프를 하게 되면 바로 RETN부분으로 가며 ZF도 1인 상태로 가게 됩니다. EAX와 EDX의 값을 확인해봅시다.

EAX는 Unregistered...이고 EDX는 Registered User이군요. Unregistered...는 우리가 창에서 본 첫번째 입력칸에 적혀 있는 문구입니다. 그렇다면 이 부분을 Registered User로 고치고 실행해봅시다.

값을 바꾸고 실행해봅시다.

ZF가 1이 반환되어 JNZ에서 점프를 하지 않는 것을 하지 않는 것을 알 수 있습니다. 계속 한줄씩 실행해봅시다.

더 말이 필요하겠습니까? 403B2C로 들어갑시다.

마찬가지로 EAX,EDX를 비교합니다.

12345는 입력한 값, 비교하는 값은 GFX-754-IER-954이군요. 해봅시다.

성공이군요. 등록키를 입력해봅시다.

네 이것으로 문제해결을 마치겠습니다.

 

'codeengn' 카테고리의 다른 글

codeengn - Advance RCE level 1  (0) 2016.08.03
codeengn - basic rce level 6  (0) 2016.08.02
codeengn - basic rce level 20  (0) 2015.10.02
codeengn - basic rce level 19  (0) 2015.10.02
codeengn - basic rce level 16  (0) 2015.10.02
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 20 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 20을 눌러주세요.

위의 창을 띄울려면 crackme3.key파일안의 데이터는 무엇이 되어야 하는가?라고 되어있네요. 일단 실행해봅시다.

문제에 적힌 창과 다른 창이 띄워집니다.  올리디버그로 열어봅시다.

실행을 하면 아까 본 창이 뜨고 창을 닫으면 종료되는 것을 볼 수 있습니다. 우리가 문제에서 본 성공창을 띄우는 부분을 찾아봅시다.

밑으로 내려가니 성공문구를 출력하는 메세지박스함수가 보이는군요. 그렇다면 이 함수를 호출할 수 있는 부분을 찾아봐야겠습니다. 코드를 뒤져봅시다.

40119B에서 메세지박스함수를 띄우는 주소를 호출하고 있습니다. 그리고 그 위에 CMP가 보이는 군요. 실행을 해보니 CMP에 의해 ZF가 0이 되어서 JNZ에 의해 점프해서 호출을 막아버립니다. 일단 확인을 위해 JNZ를 JE로 바꾸고 실행해봅시다.

ZF가 0이기 때문에 JE는 점프를 하지 않고 바로 다음줄로 갑니다.  그리고 메세지박스함수를 호출합니다.

예상대로 메세지박스함수가 호출되었습니다. 그런데 문제와는 다르게 CodeEngn! 문구는 없고 그냥 !만 출력되었습니다. 일단 문구는 잠시 접어두고 메세지박스함수가 호출이 되도록 만들어봅시다.

호출이 되도록 할려면 CMP AL,1 에서 ZF가 1이 되도록 해야합니다. 그럴려면 AL과 1값이 같아야 하지요. 여기서 AL이란 EAX레지스터의 8bit를 의미합니다. EAX가 32bit인데 그 중 8bit만을 지칭할때 AL이라고 합니다. 확인을 위해 CMP에 브레이크를 걸고 실행합시다.

레지스터부분을 확인해 봅시다.

EAX가 가리키는 주소에 문자열이 들어가 있군요. 그리고 여기서 AL은 8bit라고 했으므로 0E가 됩니다. 즉 0E랑 1이랑 비교하는데 값이 달라서 ZF가 0이 되버립니다. 그렇다면 이 EAX값을 어디서 받는지 확인해봅시다.

CMP바로 위의 코드를 보시면 401187에서 EAX값을 빼내오는 것을 보실 수 있습니다. 스택값을 확인해 봅시다.

스택에 저장된 값 0040210E를 빼내어 EAX에 저장시킵니다. 그렇다면 다시 처음부터 시작해서 어느 시점에 스택주소 0018FF88에 값이 저장시키는지 확인해봅시다. F8키를 이용하여 한줄 한줄 코드의 흐름을 봅시다.

얼마 가지 않아 401037에서 스택에 40210E를 저장시키는 것을 확인할 수 있습니다.

 마찬가지로 스택에 값이 저장되는군요. 우리는 앞서 몇번의 삽질로 0040210E가 실패로 가는 값임을 알고 있습니다. 즉 스택엔 0040210E값이 저장되면 안됩니다. 그래서 저장을 막기 위한 방법을 찾기 위해 코드를 올려보니 위에 CMP문구가 보입니다.

EAX와 -1을 비교하는 군요. CMP부분에 브레이크를 걸로 EAX값을 확인해봅시다.

EAX값이 FFFFFFFF이군요. 메모리상에서 FFFFFFFF는 00000000에서 1을 뺀 값입니다. 즉 -1이지요. 결국 CMP와 비교하여 ZF가 1이 되고 JNZ에서 점프가 되지 않아  스택에 0040210E가 저장됩니다. 우리는 이를 막아야합니다. 그럼 EAX가 왜 FFFFFFFF를 저장시키는지 알아봅시다.

EAX는 함수의 반환값을 저장시키는 레지스터입니다. 바로 위의 코드를 보니 함수 하나를 호출하는 군요.

CreateFileA함수를 호출하네요. 이 API함수는 파일을 생성하거나 읽어들이는 함수입니다. 그런데 함수의 반환값이 -1이라는 것은 파일을 만들거나 읽어들이는데 실패했다는 뜻입니다. 그런데 함수를 자세히 보면 Mode 부분에 OPEN_EXISTING라고 되어있습니다.

즉 이 CreateFileA함수는 파일을 읽어들이는 용도로 쓰이는 함수입니다. 그런데 실패했다는 것은 파일을 못읽었다는 것이지요. 파일명을 보니 CRACKME3.KEY라고 되어있네요. 아무래도 이 파일이 있어야 정상적으로 EAX값을 반환하는 것으로 보입니다.

파일을 한 번 만들어봅시다. 그런데 어떻게 만들어야 할까요? 간단합니다. 그냥 메모장을 열고 파일명을 CRACKME3.KEY로 저장시키면 됩니다.

아 그런데 우리는 이 함수가 어디에서 CRACKME3.KEY를 찾는지를 모릅니다. 확인을 위해 함수를 호출하는 부분에서 F7키로 진입하여 어떤 경로에서 파일을 찾는지 알아봅시다.

대략 7527C4E1부분에서 바탕화면에 있는 CRACKME3.KEY를 찾고 있는 것을 알 수 있습니다. 바탕화면에 만들어줍시다.

올리디버그를 종료하고 메모장을 열어 바탕화면에 RACKME3.KEY이름으로 저장합시다.

저장이 완료되었으면 올리디버그로 다시 프로그램을 열어 실행해봅시다.

함수가 호출되고 난 후 EAX값이 정상적인것을 확인할 수 있습니다. 계속 한줄씩 실행해 봅시다.

실행을 하다보면 위와 같은 코드가 보입니다. 4021A0의 4byte값과 16진수(12)를 비교하여 ZF가 0일경우 JMZ에 의해 점프되는 코드입니다. 문제는 이 점프되는 주소가 아까 스택에 0040210E를 집어넣는 주소라는 것이지요... 역시 피해가야 합니다. 덤프창에서 4021A0 주소로 찾아가 값을 확인해 봅시다.

값이 없네요... 그렇다면 코드중에서 4021A0과 관련된 코드를 찾아봅시다.

바로 위의 00401054에서 004021A0에 값을 푸쉬한다고 나와있습니다. 그리고 옆에 함수에도 주소가 나와있네요. 함수명이 ReadFile인 걸로 보아 파일을 읽어들이는 함수 인  것 같습니다. 그리고 pBytesRead에 004021A0주소가 적혀있는 걸로 보아 파일을 바이트단위로 읽어 그 값을 004021A0에 넣는 것 같습니다. CRACKME3.KEY의 크기를 확인해봅시다.

0바이트라고 나와있네요. 그래서 004021A0의 값이 0이었던 거군요. 분명 아까 CMP에서는 12라고 적혀있었으니 우리는 파일을 18바이트로 맞춰줄 필요가 있습니다. 아 왜 18바이트나면 CMP의 12는 16진수이기 때문에 우리는 16진수 12를 10진수로 바꾼 값 18로 맞춰줘야 합니다. 오른쪽마우스를 눌러 편집을 눌러주세요. 편집하실때에는 올리디버그를 종료하셔야 합니다.

누르면 메모장이 뜨실텐데요. 대충 18바이트 맞춰주세요. 한글은 2byte이고 영문,숫자는 1byte입니다.

맞춰주었으면 저장하시고 올리디버거로 열어서 실행해봅시다.

함수를 호출하고 CMP부문으로 가서 확인하면 4021A0에 12가 저장된 것을 볼 수 있습니다. 이로 인해 JNZ를 무효화 시켰습니다. 계속 한줄씩 실행해봅시다.

세번째 CMP를 발견하였습니다. 그리고 그밑에는 생소한 명령어들이 보이는 군요. 하나씩 설명해드리겠습니다.

1. SETE AL  - ZF값이 1일 경우 AL을 1로 지정. ZF가 0일 경우 AL을 0으로 지정

2. TEST AL,AL  -  AL과 AL을 서로 AND연산하여 값이 TRUE일 경우 ZF값을 0으로 지정. 값이 FALSE일 경우 ZF값을 1로 지정

3. JE - ZF가 1일경우 점프

입니다. 우리는 최종적으로 JE에서 점프를 하지 않아야 합니다. 점프를 하게 되면 우리가 여태까지 피해왔던 코드인 스택에 40210E값을 집어넣는 코드를 만나게 됩니다.  그러므로 우리는 ZF를 0으로 만들어 점프를 하지 못하게 해야합니다.

그런데? 여기서 예리하신 분들은 질문을 하실 수 있습니다.

'JE명령어 바로 다음코드에도 0040210E값을 스택에 넣으라는 코드가 있는데 이렇게 되면 어떻게 되든 스택에 0040210E을 집어넣는 것이 아닌가요?'

맞습니다. 최종적으로 어떻게든 스택에는 0040210E가 들어갑니다. 하지만 최종적으로 한가지가 다른 부분이 있습니다. 같이 한번 살펴봅시다. 전체 코드에서 스택에 0040210E란 값이 들어가는 코드는 딱 두군데 입니다.

두 코드의 차이점을 찾으셨습니까? 두번째 사진을 자세히 봐주십시요.

두번째 사진에선 스택에 40210E값을 넣고 ADD ESP,4 코드를 실행하여 현재 스택주소의 값을 4증가시켜 버립니다. 즉 이게 무슨 말이냐 하면 18FF84란 스택 주소에 40210E값을 집어넣고 스택주소를 증가시켜 현재 스택의 위치를 18FF88로 만든다는 것이지요. 그렇게 되면 나중에 코드에서 POP EAX를 수행할 때 18FF84가 아닌 18FF88에서 값을 꺼내오기 때문에 실패로 되버리는 40210E값을 꺼내오지 않는다는 뜻입니다.

말이 너무 길었군요. 결론만 말씀드리자면 JE에서 점프 하지 않도록 ZF를 0으로 만들자 입니다. 그럼 어떻게 해야할까요? 거꾸로 한번 가봅시다.

1. ZF가 0이 될려면 TEST AL,AL에서 ZF값이 0이 되어야 함. 즉 AL과 AL을 and연산하여 0이 아닌 값이 나와야 함.

2. AL과 AL을 and연산하여 0이 아닌 값이 나오게 할려면 AL은 00을 제외한 값이 되어야함.

3. AL이 00이 되지 않을려면 ZF가 1이 되도록 해줌으로써 SETE AL에서 AL이 01로 세팅되게 해주어야 함.

4. CMP부문에서 ZF가 1이되도록 해주어야 함.  즉 EAX값과 4020F9의 값이 같아야함.

결국 4번만 해결하면 나머지는 자동으로 해결이 되는 것을 알 수 있습니다. 어디한번해결해봅시다. 4020F9의 값을 확인해봅시다.

읽을때는 리틀엔디언방식으로 읽어야하니 123450F1입니다. 이젠 EAX값을 확인해봅시다.

EAX값은 31313131입니다. 뭔가 부자연스러운 값입니다. 여기서 우리는 16진수31이란 값이 아스키코드로 1이라는 것을 알아야 합니다. 즉 우리가 CRACKME3.KEY에서 입력한 값중 일부를 끌고와 16진수값으로 EAX에 저장시킨다는 것을 알 수 있습니다. 31이 4개이므로 4개의 글자를 끌고 왔겠군요. 어느 부분을 끌고 왔는지 알아보기 위해 값을 한번 바꿔보겠습니다. 이 작업은 따로 사진을 안올리겠습니다.

삽질 결과 18글자의 마지막 4글자를 갖고오는 것을 알 수 있었습니다. 그렇다면 그 4글자를 123450F1로 맞춰주어야 합니다. 아스키코드로 입력할려니 12같은 경우는 아스키코드 입력이 불가능해서 그냥 헥스값으로 맞춰주겠습니다. 헥스에디터로 파일을 열어주시고 123450F1으로 수정해줍시다.

레지스터에서 값을 읽어들일땐 리틀엔디언방식으로 읽으니 반대로 값을 입력해줍시다. 수정을 하였으면 올리디버그로 파일을 열어 실행하여 401093부분으로 가서 확인해봅시다.

EAX값이 성공적으로 수정되었습니다. 이제 코드가 진행되면서 JE구문에서 점프를 하지 않을 것입니다. 실행해봅시다.

실행을 하게 되면 성공적으로 창을 띄울 수 있습니다. 그런데 말입니다. 출력된 문자열이 엉망입니다. 우리는 CodeEngn!을 띄워야 비로소 최종적으로 문제를 푼 것입니다. 이러한 문자열을 어디서 받아오는 건지 살펴봅시다. 코드에서 메세지박스 부분을 살펴보겠습니다.

40216A에서 값을 받아오는 군요. 덤프창으로 확인합시다.

보시다시피 이상한 값이 들어가 있습니다. 새로 시작해서 40216A를 살펴봅시다.

문자열 부분이 비워있는 것을 볼 수 있습니다. 한줄씩 실행하여 어느 부분에 40216A를 집어넣는지 봅시다.

401373에서 코드를 실행 후 40216A에 값이 들어가는 것을 볼 수 있습니다. 코드를 보니  ESI의 값을 EDI에 집어넣는 것을 볼 수 있습니다. 레지스터를 확인해 봅시다.

402176에 402008을 집어넣는군요. 402008주소의 값을 확인해봅시다.

메세지박스에서 본 문자열이 적혀있습니다. 새로시작한 후 주소를 확인해봅시다.

비어있습니다. F8키를 눌러 언제 삽입되는지 알아봅시다.

ReadFile함수를 호출하고 난뒤 402008에 우리가 입력한 데이터값이 들어가는 것을 볼 수 있습니다. 다만 메세지박스함수에서 뜬 문자열이랑 값이 다르군요. 계속 한줄씩 실행해봅시다.

401074의 401311함수를 호출하고 문자열이 바뀌는 것을 볼 수 있습니다. 그럼 저 안에서 문자열처리를 하는군요. F7키로 들어갑시다.

대충 위의 명령분을 반복함으로써 문자열을 특정규칙에 의해 바꿔서 저장시키네요.

대충 요약하면

1. KEY의 첫번째 값을 HEX값으로 AL(31)에 저장하여 BL(41)이랑 XOR연산후 AL에 저장시킴

2. BL을 1개 증가시킴

3. AL이 0이 아니면 CL을 하나 증가시키고 1,2를 반복.

대충 이런 식인데요. KEY의 첫번째 값을 HEX값으로 AL(31)에 저장하여 BL(41)이랑 XOR연산후 AL에 저장시킨 후 AL이 0이 아니면 다시 반복하여 KEY의 두번째 값을 HEX값으로 AL(31)에 저장하여 BL(42)이랑 XOR연산하여 402009에 저장시키는 구조입니다. 그리고 최종적으로 저장된 CL개수만큼 메세지박스함수에 변환된 문자열을 출력시킵니다. 우리가 만들려는 문자열은 CodeEngn!으로 만드러야 하므로

KEY의 첫번째 값 (XOR) 41 을 하여 C가 나오도록 하는 구조로 만들어야 합니다.

CodeEngn을 HEX값으로 바꾸면 43 6F 64 65 45 6E 67 6E 이니까 정리를 하면

KEY의 첫번째 값 (XOR) 41 을 하여 43

KEY의 두번째 값 (XOR) 42 를 하여 6F

KEY의 세번째 값 (XOR) 43 을 하여 64

.... 중략

입니다.  !가 왜 없냐면 아까 402008의 문자열을 봤을때 느낌표는 없었는데 메세지박스에서 출력된 문자열은 !가 있는 걸로 보아 함수를 호출하면서 !를 자동으로 붙이는 것 같아 일부러 안넣었습니다.

마지막으로 XOR연산은 두 값을 이진수형태로 바꿔서 값이 서로 다르면 1 같으면 0으로 연산합니다.

EX) 1101과 1110의 XOR 연산

1101

1110

0011     답은 0011

연산과정은 일일이 올리지 않겠습니다.

연산결과 : 02 2D 27 21 00 28 20 26 즉 이것이 CodeEngn으로 변환되는 KEY값입니다.

CRACKME3.KEY를 헥스에디터로 열어 수정해줍시다.

파일을 실행해서 확인해 봅시다.

문자열변환과정을 거치니 성공적으로 바뀌었습니다. 그런데 앞에 말씀드렸던 것처럼 CL값만큼 메세지박스함수에 출력시킨다 했습니다. 우리는 8개만 출력시켜야 하는데 Cl값은 8을 초과했기 때문에 CL이 8인 시점에서 멈춰야 합니다. 앞의 변환과정에서 AL이 0이면 중단한다고 했으니 AL을 0으로 만들어 변환과정을 멈추도록 합시다.  AL을 0으로 만들려면 AL XOR BL을 해서 0이 나와야 하므로 AL값을 BL값과 맞춰줘야합니다. CodeEngn을 변환하고 난 뒤의 BL값은 49입니다. 즉

02 2D 27 21 00 28 20 26뒤에 49란 값을 넣은 02 2D 27 21 00 28 20 26 49로 수정시켜봅시다.

다시 실행해봅시다.

CodeEngn을 만들고 CL은 8이 되었습니다. 실행해봅시다.

그런데 실행을 하면 창이 안뜨는 것을 볼 수 있습니다. 관련된 코드로 가봅시다.

비교값이 바뀐 것을 알 수 있습니다.

파일의 끝 4자리 수를 7B 55 34 12로 맞추어봅시다.

수정 후 올리디버그로 열어 실행해봅시다.

성공적으로 문제와 같은 메세지가 출력되었습니다. 이때의 CRACKME3.KEY값을 정답으로 한다했으니 정답은

02 2D 27 21 00 28 20 26 49 ?? ?? ?? ?? ?? 7B 55 34 12입니다.

??부분은 어떤 값이 들어와도 저 성공메세지함수를 출력하기 때문에 ??로 표현했습니다. 물론 이렇게 되면 정답이 너무 많아지기 때문에 문제에서도 여러개의 정답이 있다고 표현한 것이며 인증이 안된다고 나오면 게시판에 비공개로 올려주시면 정답을 확인시켜 준다고 합니다.

네 이것으로 문제풀이를 마치겠습니다. 감사합니다.

 

'codeengn' 카테고리의 다른 글

codeengn - basic rce level 6  (0) 2016.08.02
codeengn - basic rce level 5  (0) 2016.08.02
codeengn - basic rce level 19  (0) 2015.10.02
codeengn - basic rce level 16  (0) 2015.10.02
codeengn - basic rce level 18  (0) 2015.09.25
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 19 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 19를 눌러주세요.

 

이 프로그램은 몇 밀리세컨드 후에 종료 되는지 묻고 있습니다.

여기서 밀리세컨드란 millisecond를 말하며 시간의 단위입니다. 줄여서 ms라고 쓰이며 1ms는 1000분의 1초입니다.

즉 10ms = 100분의 1초, 100ms = 10분의 1초 , 1000ms = 1초 입니다.

프로그램을 받아 실행시켜봅시다.

위와 같이 창이 뜨고 어느정도 시간이 흐르니 창이 자동으로 닫히는 것을 볼 수 있습니다. 즉 창이 뜨고 닫히기까지의 시간을 ms단위로 구해야하는 것이 문제인 것 같습니다. 올리디버그로 프로그램을 열어봅시다.

첫 줄에 PUSHAD명령어가 있는 것으로 보아 UPX로 패킹되어 있을 확률이 높습니다.

PEID로 확인해 봅시다.

예상대로 UPX로 패킹되어 있습니다. UPX패커를 이용해서 언패킹해줍시다.

성공적으로 파일을 언패킹 했습니다. 언패킹된 파일을 열어봅시다.

정상적으로 패킹이 되었는지 실행해 봅시다.

???? 실행을 하니까 위와 같은 창이 뜨면서 프로그램이 강제종료 됩니다. 해석을 해봅시다.

컴파일된 AutoIt 스크립트 입니다. AV 연구가들은 avsupport@autoitscript.com으로 연락주세요

라고 되어있는 것을 확인할 수 있습니다.  그러면 우리는 여기서 이 파일이 Autoit로 만들어졌다는 것을 알 수 있습니다. 그러면 간단합니다. Autoit 전용 디 컴파일러를 써 봅시다. Exe2Aut프로그램을 사용해봅시다.

실행하고 그대로 파일을 끌어다 놓으면 MsgBox함수의 소스가 나옵니다.

autoit에서 msgbox는

msgbox( 0, [창제목], [창 내용], 옵션) 입니다. 여기서 옵션은 여러 옵션이 될 수 있는데 제 생각엔 아마 창이 닫히기까지의 시간이라고 생각합니다. 그렇게 생각하는 이유는

소스를 보시면 아시다시피 메세지박스함수 다음의 코드를 보시면 시간 관련 함수를 찾지 못합니다. 즉 이 말은 메세지박스함수 안에서 시간까지 처리하는 것으로 볼 수 있습니다. 그렇기에 저기 나와있는 숫자 11.12는 닫히기까지의 시간이라고 볼수 있습니다.

11.12ms라고 하기엔 너무 짧으니 11.12초가 맞겠군요. 다만 ms로 찾아야 하니

11.12 * 1000 = 11120ms 가 되겠군요. 입력하러 가봅시다.

성공적으로 다음 문제가 뜹니다.

네 이것으로 문제풀이를 마치겠습니다.

 

'codeengn' 카테고리의 다른 글

codeengn - basic rce level 5  (0) 2016.08.02
codeengn - basic rce level 20  (0) 2015.10.02
codeengn - basic rce level 16  (0) 2015.10.02
codeengn - basic rce level 18  (0) 2015.09.25
codeengn - basic rce level 17  (0) 2015.09.25
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 16 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 16을 눌러주세요.

또 시리얼이군요. 파일을 받아 봅시다.


이름을 입력하라는군요.

뭐 당연한 결과지요. 올리디버그로 열어 봅시다.

파일을 열고 재생버튼을 누른 다음 텍스트를 찾아봅시다.

Wrong password 라는 문자열이 보이는군요. 한번 들어가 봅시다.

Good 이라는 성공문자열과 Wrong 이라는 실패문자열이 있습니다. 그리고 그 위쪽에 CMP 비교구문이 있는 것을 알 수 있습니다.

EAX와 DWORD PTR SS:[EBP-3C]를 비교한다는 군요. DWORD PTR SS:[EBP-3C]는 메모리주소[EBP-3C]에 저장된 값을 의미합니다. EBP값에서 3C를 뺀 메모리주소에 저장된 값이라는 뜻입니다. 그리고 앞에 DWORD는 4byte를 의미합니다. 

그리고 밑에는 조건점프인 jnz가 있습니다. 비교함수의 두 변수값이 다를 경우 점프하지요. 지금 점프하는 주소를 보시면 실패문자열이 있는 주소입니다. 그렇기 때문에 jmz에서 점프하지 않아야 성공할 수 있습니다.

즉 EAX와 DWORD PTR SS:[EBP-3C]이 같으면 성공할 수 있습니다.

그러기 위해선 EAX와 EBP값이 뭔지를 알아낼 필요가 있습니다. CMP부분에 브레이크를 걸고 프로그램을 실행시켜 봅시다.

엔터를 쳐주시면 브레이크부분에 걸리게 됩니다.

EAX가 5인걸로 보아 패스워드 인 것 같습니다. Name은 문제에서 정해준 CodeEngn이므로 굳이 찾지 않아도 됩니다.

EBP값이 28FF48이군요. 여기에서 3C를 빼야 합니다. 16진수 계산하기 귀찮으니 그냥 계산기 씁시다.

계산기를 실행시킨 후 보기 - 프로그래머용 을 클릭하여 16진수를 계산합시다.

16진수 이므로 Hex로 바꿔주신 후 계산을 해주시면 28FF0C가 나오네요.

즉 메모리주소 28FF0C에 있는 값의 4byte를 EAX와 비교하겠네요. EAX와 같아야 성공문자열이 나오고 EAX는 메모리주소 28FF0C에 있는 값의 4byte이니 메모리주소 28FF0C에 있는 값의 4byte가 이번 문제의 정답이 되겠군요. 얼릉 메모리주소를 확인해봅시다. 아래와 같이 들어갑시다.

메모리 주소로 들어가셔서 뒤져보시면 아까 계산한 28FF0C주소를 찾으실 수 있습니다.

값은 97 0D C6 E4 C4 10 35 00 이네요. basic rce level 15에서 설명했듯이 메모리 주소는 리틀엔디언 방식으로 읽어주셔야 합니다. 즉

00 35 10 C4 E4 C6 0D 97 입니다. DWORD이므로 4byte를 들고 오면 E4C60D97이 됩니다.

즉 EAX값이 E4C60D97이 되어야 합니다. 그런데 밑의 실행결과를 보시면

패스워드에 10을 줬을 경우

EAX는 A가 되버립니다. 즉 EAX가 E4C60D97이 될려면 E4C60D97의 십진수 값을 입력해 주셔야 합니다.

설마 계산기 버려두고 힘들게 계산하지는 않겠죠?

E4C60D97을 입력 후 10진수로 바꿔주시면 3838184855가 나옵니다. 한번 확인해 봅시다.

맞다는군요. 인증하러 갑시다.

인증~

네 이것으로 문제풀이를 마치겠습니다.





'codeengn' 카테고리의 다른 글

codeengn - basic rce level 20  (0) 2015.10.02
codeengn - basic rce level 19  (0) 2015.10.02
codeengn - basic rce level 18  (0) 2015.09.25
codeengn - basic rce level 17  (0) 2015.09.25
codeengn - basic rce level 15  (0) 2015.08.18
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 18 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 18을 눌러주세요.

Name이 CodeEngn일때 시리얼을 구하는 문제네요. 파일을 받아봅시다.

흠 이름과 시리얼을 적는 부분이 나오네요.

올리디버그로 열어 봅시다. 재생버튼을 누른 후 텍스트를 확인해 봅시다.

성공과 실패 문자열이 보입니다. 들어가 봅시다.

 

JE를 이용해 성공문자열쪽으로 점프하는군요. JE는 비교함수에서 쓰이는 두 변수의 값이 같을 때 점프 합니다. 그런데? 늘 보던 비교함수 CMP가 없습니다. 그럼 뭐가 비교함수인걸까요?

위쪽의 박스친 곳을 보시면 lstrcmpi라는 함수가 있습니다. lstrcmpi는 문자열을 비교해주는 함수입니다. 즉 이 두값이 같아야 JE에서 인식을 하여 성공문자열로 점프합니다.

그런데 뭐와 뭘 비교하는지가 안나와있군요. 그래서 프로그램을 실행시켜 대입을 해보겠습니다. 실행 전 확인을 위해 비교함수 밑쪽에 브레이크를 걸어주세요.

check를 눌러주세요.

확인을 하면 두 변수에 값이 나와있는 것을 확인하실 수 있습니다.

하나는 06162370056B6AC0구요. 하나는 1로 나오는군요. 즉 시리얼은 string1 에 저장된다는 것을 알 수 있습니다. 그렇다면 Name은 위의 06162370056B6AC0이겠군요. 두 변수의 값을 같게 해줘야 하므로 시리얼을 06162370056B6AC0로 바꿔줘봅시다.

성공문자열이 뜨는 것을 볼 수 있습니다. 아무래도 이시리얼이 정답인 것 같군요.

인증하러 가봅시다.

 인증~

다음 문제가 뜨는 걸로 보아 정답인 것 같습니다.

네 이것으로 문제풀이를 마치겠습니다.

 


 


 


'codeengn' 카테고리의 다른 글

codeengn - basic rce level 19  (0) 2015.10.02
codeengn - basic rce level 16  (0) 2015.10.02
codeengn - basic rce level 17  (0) 2015.09.25
codeengn - basic rce level 15  (0) 2015.08.18
codeengn - basic rce level 14  (0) 2015.08.18
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 17 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 17을 눌러주세요.

Name을 알아내는 것이군요. Name은 한자리 라고 합니다. 무차별 대입을 막기 위해 정답인증은 Name의 MD5 해쉬값이라고 적어 놨네요. 파일을 받아 봅시다.

재생버튼을 눌러 봅시다. PUSHED가 아닌 걸러 보아 패킷된 파일은 아니군요. 바로 텍스트를 찾아 봅시다.

둘러보니까 성공문자열이 보이는군요. 한 번 들어가 봅시다.

보니까 성공문자열 말고도 다른 문자열이 보입니다. 글자를 더 입력하라는 메세지와 30글자를 넘으면 안된다는 문자열도 있군요. 흠.. 확인을 위해 프로그램을 실행시키고 문제에서 제시한 키값을 입력해 봅시다.

check it을 눌러줍시다.

글자를 더 입력하라는 군요. Name을 빼먹어서 그런가 봅니다. 아무거나 하나 적어놓고 다시 해봅시다.

??? 분명 Name은 한글자고 키값도 문제에 나온대로 했는데 계속 글자를 더 입력하라고 나옵니다. 흠.. 뭔가 이상하군요. 올리디버그로 가서 More Chars 부분을 한번 봅시다.

위에 비교함수인 CMP와 조건점프인 JGE가 있군요. CMP에 브레이크를 걸고 실행해봅시다.

아까처럼 입력하신 후 check it을 누르시고 브레이크 된 CMP부분을 한 번 봅시다.

EAX값이 1이라고 나와있네요.

여기서 JGE 조건점프에 대해 설명하겠습니다.

JGE는 앞의 CMP a,b 에서 a가 b보다 크거나 같을 때에 점프를 하게 됩니다.

즉 정리를 하면 EAX가 3보다 크거나 같아야 JGE에 의해 점프를 하게 되고 점프를 해야 More Chars 문구가 뜨지 않습니다. 여기서 EAX는 Name이란 걸 알 수 있죠,. 그런데 아까 본 숫자 1이 값을 의미하는지 아니면 자릿수를 의미하는 지 알 수가 없습니다. 그래서 다시 한번 해 봅시다.

check it을 눌러주시고 브레이크를 확인합시다.

2가 나오는군요. 즉 EAX는 Name의 자릿수를 의미합니다. 그런데?

문제에서 Name는 한자리라고 했습니다. 즉 EAX가 1이어야 합니다. 근데 그렇게 하면 조건에 맞지 않아 More Chars 문구를 뜨게 합니다. 이럴땐 그냥 조건을 바꿔주시면 됩니다.

CMP EAX,3 부분을 더블클릭하고 조건을 아래와 같이 맞춰줍시다.

이렇게 해야 EAX가 1이 되어도 조건에 맞기 때문에 JGE가 실행됩니다. 

그런데 여기서 밑으로 좀 더 내려가면 30자리 이상은 안된다는 문자열이 있습니다. 여기선 EAX와 1E를 비교하며 JLE가 쓰였습니다. JLE는 JGE와 반대로 a가 b보다 작거나 같을 때 점프합니다. JLE이므로 건드릴 필요는 없습니다.

수정이 완료되었으면 실행해 봅시다.

Check it을 눌렀는데 아무런 반응이 없습니다. 성공적으로 수정이 됐다는 것입니다.

그러면 이제 정답을 찾아야 합니다. 한글자 라고 했으므로 그냥 뭐 다 입력해보면 되겠지요. 

1~9 그리고 알파벳 소문자,대문자, 한글 그리고 기타 특수문자 등 입력 할 수 있는건 전부 입력해 봅시다.

몇번을 삽질하다보니 정답이 나왔습니다. F라는군요. F를 MD5 해쉬해봅시다.

값에 대문자가 있으므로 맞는 것 같습니다. 인증해봅시다.



정답이 맞는 것 같습니다. 네 이것으로 문제풀이를 마치겠습니다.

'codeengn' 카테고리의 다른 글

codeengn - basic rce level 16  (0) 2015.10.02
codeengn - basic rce level 18  (0) 2015.09.25
codeengn - basic rce level 15  (0) 2015.08.18
codeengn - basic rce level 14  (0) 2015.08.18
codeengn - basic rce level 13  (0) 2015.08.12
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 15 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 15를 눌러주세요.

14번이랑 문제가 똑같군요. 일단 프로그램을 다운받아 봅시다.

이름과 시리얼 입력칸이 나왔습니다. 아무거나 입력해 봅시다.

다시 시도라하네요. 올리디버그로 열어봅시다.

재생버튼을 눌러줍시다.

pushad가 없는걸로 보아 패킷된 파일은 아닌것 같습니다. 그렇다면 바로 성공문자열을 찾아봅시다. 위와 같이 들어갑시다.

성공문자열은 모르겠지만 실패문자열은 잘 보이는군요. 더블클릭 해봅시다.

이러한 실패문자열이 있으면 당연히 성공과 실패가 나뉘는 부분이 있죠. 좀 위로 올라가시면 위 그림과 같이 CMP 부분이 보입니다.

EAX와 DWORD PTR DS:[45B844]를 비교한다네요.

PTR DS:[45B844]는 메모리주소[45B844]에 저장된 값을 의미합니다. 앞에 DWORD는 4byte를 의미합니다. WORD는 2byte이지요.

즉 정리하면 EAX와 메모리주소[45B844]에 저장된 4byte값이 같으면 성공한다 라고 보시면 되겠군요. 일단 EAX를 찾읍시다.

CMP에 브레이크를 걸고 실행시켜서 아래와 같이 입력해봅시다.

Check it을 누르면 CMP부분의 브레이크에 걸립니다. 값을 확인합시다.

EAX가 2라고 나와있네요. 즉 serial은 EAX값입니다. 자 이제 문제를 풀어봅시다.

Name가 CodeEngn일때 라고 했으므로 CodeEngn을 써 줍시다.

그리고 check it을 눌러 브레이크 부분에 걸렸으면 아래와 같이 메모리주소를 확인합시다.

하단쪽을 보시면 아래 그림처럼 메모리주소창이 뜹니다.

그런데 여기서 주의하실점이 있습니다. 바로 메모리 덤프주소는 리틀 엔디언 방식으로 읽어주셔야 한다는 것입니다.

엔디언이란 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방식을 뜻합니다. 빅 엔디언, 리틀 엔디언, 미들 엔디언으로 나뉘어집니다.

빅 엔디언 방식은 큰 단위의 바이트가 앞에 오는 방식이고 리틀 엔디언 방식은 작은 단위의 바이트가 앞에 오는 방식을 뜻합니다.

자 그러면 어떻게 읽어야 할까요>

일단 주소를 들고 오면

60 61 00 00 09 00 00 00 입니다.

리틀 엔디언 방식으로 읽어야 하므로 작은 단위가 앞에 와야합니다. 바이트단위이므로 

00 00 00 09 00 00 61 60으로 읽어야 합니다.

DWORD이므로 4byte를 들고오면

00006160이 됩니다. 

즉 정리하면 EAX값은 16진수 6160값이 되어야 합니다.

근데 입력창은 10진수로 입력해야 하므로 16진수 6160을 10진수로 바꾸어 줍시다.

24928이로군요. 이 값을 프로그램에 넣어봅시다.

아무래도 정답이 맞는 것 같습니다. 그럼 인증을 해 봅시다.

정답이 맞는 것 같습니다.

네 이것으로 문제풀이를 마치겠습니다.




'codeengn' 카테고리의 다른 글

codeengn - basic rce level 18  (0) 2015.09.25
codeengn - basic rce level 17  (0) 2015.09.25
codeengn - basic rce level 14  (0) 2015.08.18
codeengn - basic rce level 13  (0) 2015.08.12
codeengn - basic rce level 12  (0) 2015.08.12
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 14 문제를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 14를 눌러주세요.

name이 CodeEngn일때 serial를 구하라는군요. bruteforce가 필요하답니다.

bruteforce는 무차별 대입이란 뜻을 가지고 있습니다. 이는 암호를 알아내기 위해 암호가 될만한 것들을 전부 대입해본다는 뜻이지요. 만약 암호가 4자리라면 0000 0001 0002 부터 시작해서 9999까지 전부 대입해서 암호를 알아냅니다. 이것을 무차별 대입이라고 합니다.

자 그럼 일단 프로그램을 실행시켜 봅시다.

음 창이 하나 뜨는군요. CHECK를 눌러봅시다.

1글자 이상을 채우라고 하네요. 그럼 채워 봅시다.

시리얼이 틀렸다면서 다시 시도하라고 나오네요. 올리디버그로 열어봅시다.

재생버튼을 눌러봅시다.

PUSHAD명령어가 있군요. 앞의 문제에서 설명했다시피 패킹된 파일인 것 같습니다.

확인을 위해 PEiD를 열어서 봅시다.

UPX로 패킹이 된 것을 알 수 있습니다.

UPX로 패킹된 파일은 맨 마지막 줄에 OEP로 갈 수 있도록 표시를 해놓습니다. 어디 한번 찾아봅시다.

마지막 줄을 보시면 특정주소로 점프시키는 명령어가 있습니다. 한번 가봅시다.

눌러주시면

알 수 없는 글자가 뭐라고 뜹니다. 재생버튼을 한번 눌러줍시다.

네 문자열이 보이는 걸로 보아 언패킹 된 부분이 나온것 같습니다.

쭉 내려봅시다.

내리시면 아래와 같은 부분이 나옵니다.


두개의 메세지 박스가 나오는데 하나는 good job이라 뜨고 하나는 아까 보신 실패한 문구가 적혀있습니다. 우리는 시리얼을 찾아야 하므로 성공부분을 자세히 봅시다.








'codeengn' 카테고리의 다른 글

codeengn - basic rce level 17  (0) 2015.09.25
codeengn - basic rce level 15  (0) 2015.08.18
codeengn - basic rce level 13  (0) 2015.08.12
codeengn - basic rce level 12  (0) 2015.08.12
codeengn - basic rce level 11  (0) 2015.08.12
Posted by englishmath
,


안녕하세요. 오늘은 basic rce level 13을 풀어보겠습니다.

홈페이지로 들어가 basic rce level 13을 눌러주세요.

정답을 찾으라는군요. 파일을 열어 봅시다.

 

패스워드를 입력하라네요. 올리디버그로 열어봅시다.

그런데 올리디버그로 여니까 바로 실행이 되는군요. 그래서 프로그램을 닫았더니

 위와 같은 메세지가 뜨면서

올리디버그의 내용이 사라져 버립니다. 아무래도 올리디버그론 풀 수 없는 문제인 것 같습니다. 이럴땐 어떻게 해야 할까요?

일단 이 프로그램이 어떤 언어로 짜였는지 어떤 패커로 패킹했는지 알아내야 합니다. 이럴 땐 프로그램을 사용하면 간단하게 알아 낼 수 있습니다. PEID란 프로그램을 사용해 봅시다.

사용법은 정말 간단합니다. 그냥 ^^^를 눌러 알아볼 파일을 열어주시면 됩니다.

밑에 보시면 net을 이용하는 마이크로소프트 C#으로 제작이 된 것 같습니다.

visual이 쓰인걸로 보아 visual c#로 컴파일 된것 같습니다. 컴파일이라는 것은 인간이 작성한 고급언어를 컴퓨터가 알 수 있는 기계어로 번역시키는 것을 의미합니다. 하지만 우리는 기계어를 모르기 때문에 우리가 알 수 있는 고급언어로 번역시켜 줄 필요가 있습니다. 기계어를 고급언어로 번역시키는 것을 디컴파일 이라고 합니다. 디컴파일 프로그램을 사용해 봅시다.

여러가지 프로그램이 있지만 이번문제에서는 널리 알려진 C# .NET DecompilerReflector을 사용해 보겠습니다.

실행을 했으면 가져올 파일을 선택 후 리플렉터 안으로 드래그 앤 드롭을 해주시면 됩니다.

그러면 밑에 하나가 추가되는 것을 볼 수 있습니다.

+버튼을 눌러 세분화를 시켜보면 Main소스부분이 나옵니다.

소스를 확인했으면 위로 올라가 오른쪽 마우스를 눌러 disassemble를 눌러주세요. 디셈블을 하는 것입니다.

그리고 저장합시다. export를 눌러줍시다.

그리고 start를 눌러주시면 해당 경로에 파일이 저장됩니다.

완료되었으면 경로를 복사해 아무폴더주소에 붙여주시면 됩니다.

그러면 아래와 같이 파일이 뜹니다. 확인하셨으면 이제 파일을 열어봐야 겠지요?

확장자가 cs이므로 c#파일입니다. 파일을 여시면

위와 같이 소스가 뜹니다. 밑에 보시면 readLine와 plainText가 같을 경우 성공문자열이 나온다는군요. 우리는 정답을 알아내야 합니다. 위쪽을 보시면 plainText에 무언가를 저장시키네요. 그 값을 알기 위해 우리는 plainText를 출력해 볼 필요가 있습니다.

다음과 같이 입력해주시면

프로그램 실행시 위와 같이 정답이 뜨는 것을 알 수 있습니다.

 

 인증을 해보면

네 정답이 맞는 것 같습니다. 이것으로 문제풀이를 마치겠습니다.

'codeengn' 카테고리의 다른 글

codeengn - basic rce level 15  (0) 2015.08.18
codeengn - basic rce level 14  (0) 2015.08.18
codeengn - basic rce level 12  (0) 2015.08.12
codeengn - basic rce level 11  (0) 2015.08.12
codeengn - basic rce level 10  (0) 2015.08.05
Posted by englishmath
,

안녕하세요. 오늘은 basic rce level 12를 풀어보겠습니다.

홈페이지로 들어가 basic rce level 12를 눌러주세요.


key값과 주소영역을 찾으라는 군요. 

파일을 받아 열어봅시다.

아무래도 key값을 알아내야 하는 모양입니다. 올리디버그로 열어봅시다.

패스워드나 key, 시리얼 값을 알아낼 때에는 문자열을 보시는 것이 좋습니다. 문자열을 한 번 봅시다.

위와 같이 보시면 올바른 키를 찾았다며 축하해주는 메세지가 있습니다. 더블클릭하여 자세히 봅시다.

문구의 위쪽에 보시면 CMP 비교함수가 있습니다. EAX와 7A2896BF를 비교한다는군요.

즉 EAX-7A2896BF를 해서 0이 나오면 jnz가 인식하고 바로 아래로 넘어갑니다.

만약 위의 차가 0이 아니라면 jnz는 성공문자열을 뛰어넘은 00401098로 이동시켜줄 것입니다.

그렇다면 EAX값은 얼마가 되어야 할까요? 7A2896BF를 빼서 0이 나와야 하니 EAX값은 7A2896BF가 되겠지요. 7A2896BF은 16진수이므로 10진수로 고쳐줍시다. 2049480383가 나오네요. 그러면 이제 EAX가 뭔지 알아야겠죠? cmp 부분에 브레이크를 걸고 프로그램을 실행시켜 10이란 값을 넣어보겠습니다.

check버튼을 누르셨으면 이제 CMP쪽에 멈출것입니다.

EAX값을 확인해 봅시다.

A가 나오네요. 입력한 값이 EAX값인 것을 알 수 있습니다.

그러면 이제 다시 실행시켜 2049480383를 입력해 봅시다.

성공메세지가 나오는군요. key 값은 2049480383입니다. 그런데 이 성공메세지 대신 key값이 나오도록 hexedit로 수정하라는 군요. hexedit로 열어봅시다.

성공메세지가 있는 쪽을 블럭잡았습니다.

수정시켜 줍시다. 문제는 값을 넣을때 16진수아스키코드를 넣어야 합니다.

즉 2라는 값을 넣을 때에는 그에 맞는 16진수아스키코드인 32를 넣어줘야 합니다.

그럼 차례대로 넣어봅시다.

차례대로 넣고 남은 부분은 그냥 0으로 채워주시면 됩니다. 자 그러면 이제 0x???? ~ 0x????의 값을 알아내야겠죠?

열을 보시면 총 16개가 있습니다. 그리고 번호는 이렇습니다.

0 1 2 3 4 5 6 7 8 9 A B C D E F

32부터 시작하므로 00000D30의 B 즉 000000D3B가 시작점입니다. 0x????라고 표현했으니까 4자리만 뽑아오면 0x0D3B가 됩니다.

자 그러면 끝은 어디일까요? 보통 정상적으로 33이 끝이라고 생각합니다. 하지만 여기엔 Null이 있습니다. 문자열의 끝을 알리는 Null은 16진수로 00을 의미합니다. 즉 끝은 33이 아닌 Null을 포함한 00. 즉 0D45가 마지막입니다.

그러면 영역은 0D3B ~ 0D45 까지 입니다. key값은 2049480383이므로

합치면 20494803830D3B0D45입니다. 인증을 해 봅시다.

네 이것으로 문제풀이를 마치겠습니다.

'codeengn' 카테고리의 다른 글

codeengn - basic rce level 14  (0) 2015.08.18
codeengn - basic rce level 13  (0) 2015.08.12
codeengn - basic rce level 11  (0) 2015.08.12
codeengn - basic rce level 10  (0) 2015.08.05
codeengn - basic rce level9  (0) 2015.08.05
Posted by englishmath
,