2013.05.06 01:53 WarGame

[+] ... 


 


시간이 널널해지면 널널해질수록 블로그 글 작성 횟수가 줄어들고 있습니다.


문제를 푼건 1달 전 쯤인거 같은데 이제서야 키보드를 잡았네요.


이번 문제는 android platform이 대상입니다.


생각해보니 일반 pc 말고  mobile platform 을 대상으로 하는 wargame을 대상으로 글을 쓰는 건 이게 처음인 것 같네요.



[+] ? 


 

문제 파일은 아래 링크에서 받을 수 있습니다.

 

 

 

Bluebox 라는 Android 보안 회사에서 낸 문제입니다.

 

우리 보안이 자신 있으니 깨보아라 같은 경우가 아니라

 

회사 홍보 겸 샘플로 간단히 제작한 걸로 보입니다.

 

먼저 App을 받아 폰에서 실행 시켜보도록 하죠.

 

 

<Fig1. App 실행 화면 >

 


군더더기 없는 깔끔한 문제군요.

 

특정 String을 입력하면 통과하는 간단한 crackme 입니다.

 

이제 code를 뜯어보기 위해 App 압축을 풀어보..

 

는 풀리지 않습니다.  암호가 걸려있다는군요..

 

위 링크에 있는 unpack.py 를 통해 압축을 해제 하셔야 합니다.

 

<Fig2. unpack.py>

 

Mobile에 설치할 때는 아무 이상 없이 설치 되었는데 PC에서는 압축 해제가 되지 않는다?

 

상당히 흥미로운 주제입니다.

 

중요한 부분은 이 한줄이죠.

 

member.flag_bits ^= member.flag_bits%2

 

특정 flag를 제거합니다. 


Zip file의 format 을 확인해보면.. 암호화 여부를 판단하는 bit 임을 확인 할 수 있군요.


Android 의 apk manager는 password flag를 무시하고 설치를 시도하기에 이런 트릭을 걸 수 있습니다.


역으로 pack 하는 것도 매우 간단합니다.


Local file Header 와 Central directory file header 의 general purpose bit flag에 xor 1을 해주면 되죠.


어떠한 apk 파일이라도 쉽게 이런 트릭을 걸 수 있다는 점에서 꽤 유용해보이네요.

 

아무튼 이렇게 압축을 해제하고 decompile 해서 문제를 구성하는 간단한 알고리즘을 풀면 해결!

 

...

 

되면 이렇게 글을 쓸 일도 없었겠죠.

 

여러모로 트릭이 몇가지 씩 들어간 문제인데요.

 

코드를 확인해 보시면 아래와 같이 so file을 Load하는 것을 볼 수 있습니다.

 

<Fig2. MainActivity 에서 so file을 Load하는 모습>

 

JNI 를 통하여 so file의 함수를 호출합니다.

 

readmem 함수는 다시 search 함수를 호출하게 되고... 이 함수는

 

 

 

 

<Fig3. search 함수 >

 


 

findmagic 함수를 통해 memory 상에서 dex file이 올라간 시작 지점을 찾고 [ dex\x0a ]

 

Lava/lang/String 의 add Method의 위치를 찾습니다.

 

그 후 mprotect 함수를 사용하여 [ sub_F04 부분 ] 쓰기 속성을 준 뒤

 

memcpy 를 통해 inject 함수에 있는 assembly 를 복사합니다.

 

즉, So file에서 Memory에 Load된 String Class의 add method를 Code Injection 한 겁니다.

 

정확히 말하자면 덮어 씌운 거지요.

 

그러니까 앞서 살펴 본 decompiled code는 전혀 실행이 되지 않을 거란 겁니다.
 


[+] !




Injection 될 Code는 아래와 같습니다.

 

 

<Fig4. Injection 될 길이 0xDE의 Code>



add method가 시작하는 address에 이 code를 덮어 씌우신 후 다시 분석 하면 된다는 거죠.

 

ida를 활용하여 해당 function 의 address를 확인합시다.  직접 memory를 dump 뜬 후에 비교하는 방법으로도 address를 쉽게 구할 수 있습니다.

 

이를 통해 구한 실제 파일의 offset 은 0x27680 입니다.

 

 classes.dex파일에 저 code를 덮어 씌운 다음 Tool을 돌려보면..


 dex2jar 는 해석을 못하고 오류를 뱉습니다.


baksmali도 안되네요.


IDA도 안되요. 

<Fig. 아오.. >


 

다행히 한 Tool에서 오류가 나는 곳이 다른 Tool에서는 잘 분석 될 때도 있더군요.

 

이건 뭐 드래곤볼도 아니고 Code를 모아 소원을 빌어 문제를 해결하는 것도 아니고 ..

 

아무튼 한땀한땀 짜깁기를 하면 ..

 

<Fig5. 모은 Dalvik code>

 

뭐 아무튼 실마리는 다 모였고 Tool에서 해석되다 만 Code들과 Hand-ray를 사용하면

 

아래와 같은 Code를 얻을 수 있습니다.

 

<Fig6. Code를 다 모았으니 문제를 풀어주세요!>

 

 

사실 ... 부분은 모든 Tool이 Error를 낸 부분인데

 

다행히 4byte 정도라 manual 해석 및 추측이 가능한데요.

 

map.put 이 들어가겠죠.

 

자.. 이제 package 쪽은 다 해결 됐습니다.

 

마지막으로 본 문제쪽 Java Code를 살펴봐야 합니다

 

문제에 앞서 ..

 

한가지 퀴즈를 내볼까요?

 

Lјava/lang/String 과 Ljava/lang/String;

 

같을까요 다를까요?

 

 

 

...

 

다릅니다.

 

아니 이게 무슨 소리야..

 

ј가 j가 아니라니

 

사실 전자의 j로 보이는 문자는

 

0xD1 0x98의 Unicode 문자입니다.

 

이런 거지같..

 

그런고로

 

전자 Fake j는 출제자의 Class를 참조하고

 

후자 진짜 j는 java 기본 Class를 따릅니다.

 

까도 까도 깔게 나오는 너란 문제.. 양파 같은 문제..

 

<Fig7. Verify Botton을 눌렀을 때 호출되는 함수>

 

 

fake.String 에서 new를 통해 생성하는 건 위에서 한땀 한땀 빚어낸 Add Method를 타게 됩니다.

 

남은 잡다구리한 함수를 거쳐 생성한 String  "RKGMKAQEGJATGAVWABJKGTG" 를

 

add method에 넣고 돌려주면 답이 나옵니다.


THECHANGESAREALWABSHERE

THECHANGESAREALWAYSHERE

 

2가지네요.

 

 

<Fig8. 보고 싶던 너>

 

 


[+]  ++ 


Code injection을 통해 동적으로 Code를 바꾼다.

 

난독화에 있어 괜찮은 방법이 될 수 있을 거 같습니다.

 

특정 함수가 불릴때만 잠깐 바꾼다면 Memory dump를 통해 알아내기도 힘들겠죠.

 

물론 넣을 Code가 다 노출되는 단점이 있습니다만.. 이 또한 알아보기 어렵도록 꼬아놔야할 겁니다.

 

섞고 , 섞고, 돌리고 섞고..

 

하지만 이렇게 꼬아놔도 어쨌든 깨지는건 시간의 문제이기 때문에 많은 기업들이 이제

 

Hardware를 이용한 보안 기술 접목을 준비하고 있습니다.

 

TPM 이나 Trust zone을 사용해서 말이죠.

 

이러한 Hard 기반 보안 기술이 과연 얼마나 튼튼한 방패가 될 지는 아직 두고봐야 할 것 같습니다.


 

Posted by LinkC

2011.07.16 21:45 WarGame

[+] Introduction

 


 이번에 소개할 문제는 VM 관련 문제 입니다.

VM을 이용한 기술은 VCP [ Virtualized Code Protection ] 이 있으며 해당 기술은 Protector 에 많이 쓰이곤 합니다.

언뜻 봐도 " Code를 Virtualize 하여 Protect 한다 " 라는것을 의미한다는거라고 쉽게 추측 할 수 있죠.

상용 Packer 인 Themida에 실제로 쓰이고 있는 기술이기도 하구요.

물론 Themida에는 VCP 뿐만 아니라 여러가지 Anti Reversing 기술들이 들어가있습니다만..

 이 포스팅에서는 VM만을 다루도록 하겠습니다.

 * VM이 적용되면 Reversing 하는 입장에서는 상당히 귀찮아집니다.

뒤에서 설명하겠지만 Assembly Language 로 한줄씩 실행되기 떄문에 

전체적인 구조를 살펴보려면 Script를 짜거나 손으로 직접 모아야 하기 떄문이죠.

디버거로 열어봤는데...


<Fig 0. VM이 딱 ! >


 <Fig0-1. 5초후에 빡침이 딱!>



[+] Problem


<Fig1. Bin500을 실행 시켰을 때 >

 

먼저 Debugger로 문자열을 확인해보면

key File로 짐작되는 문자열 'codegate.key' 를 찾을 수 있습니다.

적당히 아무내용이나 집어넣어서 재실행 시켜보면

역시 유효하지 않은 파일이라고 하는군요.

<Fig2. 해당 파일이 올바르지 않을 때 메세지> 

이런 류의 문제라면 해당 Key 파일을 검사하는 부분을 우회해도 

암호가 나오지 않고 그 파일을 가지고 연산을 하기 떄문에

해당 파일의 내용을 정확히 복구를 해야 합니다.

 파일을 열어 Verify 하는 부분을 찾으려 해도 도통 보이지 않는군요.

이 문제의 핵심인 Verify 부분이 VM에 의해 실행되기 때문이죠.


[+] Analysis

 
그렇다면 Debugger로 확인을 해봅시다. 

<Fig3. VirtualAlloc을 통해 특정 메모리 영역을 할당받는 모습>

 해당 영역을 확인해보면 아시겠지만

애초에 VM 영역에서 시작하네요.

후에 VirtualAlloc 을 호출하고 특정 영역에  RWE 권한을 모두 줍니다.

계속 따라가보면 VirtualAlloc을 한번 더 호출하고 .. [ 같은 크기, 다른 위치에 RWE 권한을 줍니다 ] 

이 할당한 영역에 특정 명령어를 수행하는 것을 확인 할 수 있습니다.

<Fig4. VirtualAlloc에 할당된 영역에서 코드를 실행하고 있는 모습>
 
그 후에 다시 0x40ABBD로 Return해서 특정 루틴을 반복합니다.


<Fig5. Code를 가져와 Decrypt하는 부분>

0x0040A94A를 호출함으로써 실행할 Code를 복호화 하는데

해당 함수를 살펴보면 다음과 같습니다.


<Fig6. Fig5의 Decrypt함수 내부>

 

사실 위 함수가 문제를 푸는데 큰 도움이 되는 건 아닙니다.

CPU가 해석 할 수 있는 일반 기계어로 복호화 하는 과정이지

Key 파일의 내용을 확인하는 과정이 아니기 떄문이죠.

하지만 VM의 동작 방식은 확인을 하고 갑시다.

대략적인 VM의 구현은 다음과 같습니다.

<Fig7. VM의 동작 방식>

실제 문제 파일을 Debugging 해보면 아시겠지만

text 영역과 VM 영역이 번갈아 가며 실행되는 것을 볼 수 있습니다.

Sensitive 한 곳은 VM 처리가 되어있는거죠.



즉 우리가 원하는 것은 ' Codegate.key 파일을 입력 받고 난 후 실패 메세지가 나오기 전까지의 연산 과정 ' 입니다.

이것은 1Byte 씩 검사하여 다르면 바로 실패로 return 하는 과정일수도 있고

전체 내용을 모두 검사한 후 최종적으로 실패를 판단할 수도 있습니다.

물론 전자가 훨씬 까다로워집니다. 실행중에 비교 값을 바꿔야하니까요.

ReadFile에 BP를 걸고 해당 파일을 읽어 온 후에 Buffer에 접근 하는 부분을 잡아보면

최종 Code가 실행되는 곳을 잡을 수 있습니다.

이곳을 보면 Fig4에서 할당한 곳과는 다른 공간임을 알 수 있습니다.

즉, 복호화된 Code가 실행 되는 부분은 2군데이며 

1. 일반 적인 Code가 실행되는 부분

2. Key 파일의 내용을 검사하는 부분


이 되겠습니다.

두 부분을 모두 BP 걸고 확인해보면 아시겠지만 Call , JMP 문을 찾아 볼 수 없다는걸 알 수 있습니다.

Call이나 JMP문이 가고자 하는 곳은 VM에서는 외부 , 즉 원본 프로그램의 text 영역입니다.

이 부분으로 가려면 해당 주소에 맞는 연산이 또 별도로 필요하죠.

문제 풀이엔 별로 중요한 내용이 아닙니다만,

'VM은 이런식으로 구현되고 있다' 라는 것은 염두해두시는게 좋습니다.



[+] Solution



이 다음부턴 딱히 설명 드릴게 없습니다.

Script를 짜거나 손으로 직접 코드를 바꾸시면서 진행을 하셔야 합니다.

운이 나쁘게도 앞서 설명드린 1Byte 씩 검사하고 아닐 경우 실패로 간주하는 타입이군요.

Script로 모으기 짜증 + 1  이 되었습니다.

아무튼 해당 Code를 모으면 다음과 같은 모습입니다.

Pydbg의 HardWare BP를 이용한건데 가변길이라 그런지 

다음 명령어까지 받아오더군요.. 쩝..


<Fig8. Xor, Cmp 부분 중 일부를 긁어온 모습>

이 부분을 예로 들자면

al 로 가져온 값을 xor 0x46 하고 이 값을 cmp 합니다.

xor  [ Data  ] , 0x46

cmp ( [ Data ] ^ 0x 46 )  , 0xf0

즉 Data 의 값은 0x46 과 Xor를 했을 때 0xF0 가 나오는 0xB6 이 되겠네요.

이런 식으로 Codegate.key 값을 하나씩 복원합니다.

Codegate key 값이 총 100 Byte 니 벼..별거 아니군요.

Xor 부분과 cmp 부분을 parsing 매 Byte마다 바꿔주면

다음과 같은 원본 데이터를 얻을 수 있습니다.

<Fig9. 원본 Key File >

이를 codegate.key 에 저장하면 


<Fig10. 해독된 Key File>

이게 정답은 아니겠죠?

100Byte의 16진수가 뭘 의미 할까요.

흠 분포도를 보면 문자를 의미하는건 아닌거 같습니다.

그리고 저 출력 방식도 의심해볼만 하죠

4 * 25 형식입니다.

또, 0x80 0x00 이 유독 눈에 많이 띄는걸 볼 수 있는데..

일단 이를 binary 값으로 바꿔보았습니다.


<Fig11. Binary 값으로 바꾼 모습>



<Fig11-1. !?>
왜 4 * 25 형식으로 출력했는지 알겠네요.

0x80이 binary 값으로 1000 0000 이니까

뒤의 0을 떼버리면 25 * 25 형식의 값이 완성됩니다.

여기에 모서리 부분을 보면 1과 0이 규칙적으로 나열되어있는데

전 이걸 QR 코드라고 판단했고 이를 만들어보면..



QR Code Reader로 읽어보니

I_am_in_C0d3gat3_2011!!

이라는 답이 나오는군요.















Posted by LinkC

2011.02.27 15:14 WarGame

Padocon 문제를 기웃거리다 재밌는 문제를 발견했습니다.

Bot은 많이 들어보셨죠?

출동이다 Autobots!



아 이게 아닌가?

아무튼 위의 예시에서도 보셨다 시피

bot은 로봇의 준말입니다.

얼마 전 , 아니 요즘까지도 화제가 되는 있는 좀비 PC의 감염 원인이 되고 있는 녀석들이죠

일단 설치가 되고 나면 Command & Control Server에 접속해서 공격자의 명령에 따르는 착실한 종이 됩니다.

보통 IRC를 이용하여 공격자의 명령을 하달하곤 했는데 

요즘은 Twitter를 이용한 악성 Twit Bot 이 등장했습니다.

이번 문제에서 이용한 것도 Twit Bot 이구요.


[+] Dynamic Analysis


파일을 실행시켜 보면 먼저 hint.jpg 라는 파일이 생깁니다.



<그림1. Hint.jpg>


흠. 기존의 Bot의 구조도와 다르지 않습니다만 명령을 전달하는 것이 Twitter가 된다는 점이 흥미롭군요.

아무튼 이 hint에 직접적인 답은 없는 거 같고, 현재 Bot이 이런 원리로 돌아가고 있다는 것을 알려주기 위해서 생성된 거 같군요

Bot 이면 분명 명령을 하달하는 어느 Site에 접속을 할 것이고, 이 경우 특정 Twitter에 접속하겠죠.

나가는 Packet을 잡아서 확인해봅시다.


<그림2. Wire Shark 로 Capture 한 Packet>

확인해보면 fuck1224 라는 Twitter 계정으로 접근 하고 있는 것을 확인 할 수 있습니다.

바로 접속해보죠.


<그림3. Fuck1224 계정의 time line>

흠 문제가 쉽게 풀리는거 같군요.

분명 저기있는 알수 없는 문자들 중 하나가 답일 겁니다.

Base64로 Encoding 되어 있는거 같네요. 이걸 Decoding 해보면 답이 쨘!

어때요 참 쉽죠?

[ONL[Y|Dfzce}}D#}`/hfi.o|gg#~~t.abje+n

4J :ZZHIxoe {jecyoom4mstN+_un

}}S#PA|Dfi.ofzce0#

rj: M.KE$U0dph49Vaer}zTw"j7c,?t]#1c

으..으읭?

머리속엔 풰이크다, 이 볍진아 라는 플짤이 반복 재생되고 있습니다.

뭐 이렇게 쉽게 풀릴리가 없겠죠.

아무래도 문제 Binary의 정적 분석이 필요할 것 같습니다.



[+] Static Analysis


이것 , 저것 다 떼고 핵심 함수만 살펴보죠.

해당 Twitter에서 문자열을 받아 이를 Command 로 해석하는 부분을 봐야합니다.

String 을 뽑아내니 어딜 봐야 할지 답이 나오네요.

DOWNLOAD, DDOS, STOP ...

저 함수가 분명 할겁니다.

<그림4. IDA 로 뽑아낸 Binary의 String>

해당 함수를 살펴보면 인자로 Twitter Time line 에 나왔던 문자열을 받는 것을 볼 수 있습니다.

Decoding 하는 함수를 분석 해서 할 수도 있겠습니다만

그냥 인자를 넘겨줄때 저희가 원하는 문자열을 넣으면 되겠죠.

아마 가장 첫번째 문자열일거라고 생각합니다.

해당 문자열을 넣어보면.. 

cmo6IE0uS0UkVTBkcGg0OVZhZXJ9elR3Imo3Yyw/dF0jMWM=



<그림5. 원하는 문자열을 넣고 Decoding 완료 시에 BP로 잡아낸 모습>

저게 답이 겠죠?



[+] Etc



이런식으로 Twitter를 이용해 악성 Bot에게 명령을 내리게 되면

이를 추적하기가 상당히 난해해집니다.

서울에서 Bot에게 명령을 내리든, 부산에서 내리든, 해외에서 내리든 

Bot은 정상적으로 동작하기 때문에 공격자의 위치를 특정하기가 굉장히 어렵다고 하는군요.

Social Network가 한창 인기를 얻어 부상함에 따라 Bot도 유행을 따라 Twitter에 탑승하는군요.

각 AV사에서도 지금 알려진 Twit bot들에 대한 엔진 업데이트를 마친 상태입니다.

보안은 영원한 창과 방패의 대결이랄까요. 



아무튼 요즘 문제시 되는 상황에 맞는 재미있는 문제였다고 생각합니다 :D

출제자 분들에게 박수를! 




Posted by LinkC

2010.08.28 13:45 WarGame

1년 전쯤에 Saphead가 주최한 Hackjam 대회가 있었습니다

문제마다 만화로 그려내서 상당히 재밌었는데요

폴더 정리를 하다가 문제를 발견해서 풀이를 올립니다

이번 문제는 Hacking에 대한 지식을 시험하기보다는

Hacker로서의 기본 소양인 코딩을 시험하는 문제였습니다

바로 Game of life의 룰을 숙지하고 이에 맞도록

코딩을 하는 것이 해당 문제의 목표였죠

해당 문제의 포트에 접속해보면

다음과 같은 화면을 보시게 됩니다

<그림1. 문제에 접속하면 맞이하는 화면>


#은 벽이고

*는 한 점을 나타내게 됩니다

좀 더 쉽게 이해하시려면 다음 사이트를 방문하셔서

직접 플레이 해보고 룰을 익히시는게 좋겠죠

http://www.bitstorm.org/gameoflife/

 
<그림2. Game of life의 실제 플레이 모습>



이제 문제가 이해가시나요?

아래 적혀진 < : 숫자 > 는 바로 얼마만큼 진행을 시키는가 입니다

그림1을 보면 저 벽을 유지한채로 12단계를 진행한 것을 Recive 하기를 원한다는거죠

OverFlow, FSB 등이 아닌지라 착실하게 풀어나가는 방법밖에 없습니다

이 게임의 룰은 다음과 같습니다


<그림3. Game of life의 룰>


자기 자신을 기준으로 8칸의 Cell을 검사한 뒤에 해당 룰을 따르게 되는데

그 Cell이 점유되어 있는가 없는가에 따라 약간 달라집니다

이웃이 없거나 , 1개 있을 경우 사라지고

2,3개는 그대로 남으며

4개 이상부터는 사라집니다

만약 Cell 내에 아무것도 없다면

3개의 이웃이 있을 경우 Cell을 점유합니다

문제를 풀어서 해당 port로 보내게 되면 아시겠지만..

한번만 풀면 돼는게 아니라 16라운드 까지 풀어야 합니다

1라운드 , 2라운드... 16라운드까지 풀어야

비로소 정답을 얻게 되죠

뭐 일단 1라운드를 깰 알고리즘을 짰다면

나머지는 별로 어렵진 않죠




문제가 포함하고 있는 문자열인 ###을 포함하지 않은 메세지를 받을 때까지

문제 풀이 루틴을 돕니다

다만 list 형식으로 일일히 나눠주고

다시 정답형식에 맞는 format 으로 바꿔주는게 귀찮더군요

아무튼 이렇게 돌려주면


<그림4. PassWord GET!>
Posted by LinkC

2010.08.23 01:01 WarGame

저번 문제와 같이 바이너리를 얻을 수 없는 관계로

vnsecurity에서 작성한 문서를 토대로 제가 이해한 내용을 써내려가는 식의 포스팅을 하도록 하겠습니다


문제는 대략 메모를 남기는 프로그램을 Overflow 취약점을 이용해 쉘을 따는것 같습니다

여기서 핵심은 메모를 남기는 buffer의 크기가 매우 작아서, 쉘 코드가 들어갈 수 없다는 것입니다

쉘 코드를 나눠서 메모를 여러번 남김으로써, Exploit 하는 문제죠

먼저 문제 코드를 살펴보겠습니다


한가지 특이점은 29번째 줄의 

 if ( !setjmp(exception_env) )   


38번째 줄의
 
longjmp(exception_env, 1);   


라는 코드가 쓰인 것입니다

setjmp / longjmp 문에 대한 설명은

http://studyfoss.egloos.com/5275830 에서 얻을 수 있었습니다


setjmp/longjmp는 프로그램의 흐름을 비정상적으로 제어하는 것으로 이른바 nonlocal goto라고 불린다.
nonlocal이라고 하는 것은 일반 goto와 달리 함수 밖의 위치로 이동할 수 있기 때문이다.
하지만 아무런 제한없이 아무 함수로나 움직일 수 있는 것은 아니며
이동할 위치의 stack frame이 보존된 상태여야 한다.
(즉, 해당 함수가 아직 실행되고 있는 상태에야 한다.)
일반적으로 중첩된 함수 호출내에서 예외 상황이 발생한 경우
상위의 예외 처리 루틴으로 바로 제어를 넘겨서 실행할 수 있도록 구현할 수 있다.

그러니까 요약하자면

setjmp에서 저장한 레지스트리 값, 스택 구조는 복원하되, 스택 내용은 복원되지 않는다

라는 것이군요

먼저 한번의 메모 기록에 들어갈 수 있는 쉘 코드의 크기는 17byte 입니다

전체 메모 크기가 30 byte 지만

44번째 줄의

" Memo : < Shellcode> , size : <Code size> "

의 부가 설명 덕분에 13byte가 빠지게 됩니다

여기서 우리가 Shellcode 를 넣으려고 하는 Buffer는

memo_array[30][30] 이고 , 첫번째 기록한 메모와 두번째 메모와의 Gap 은 13byte 가 되므로

쉘코드 뒤에 JMP 13 명령어를 넣어주어야 할 것입니다

대략


<그림 1. 메모 1개 기록 할때의 memo_array[n][30] 구조>

그리고 메모를 모두 기록했다면, 마지막으로 memo_array의 주소로 JMP 해야 합니다

여기서 바로 longjmp 가 쓰이게 됩니다

longjmp를 조작해서 setjmp 가 아닌 Shellcode 가 들어있는 memo_array 의 주소로 JMP 하면

일사 천리로 진행되겠죠

37번째 줄의 OverFlow 를 이용합시다

여기서 메모리 구조를 살펴보면


<그림2. bss 구역의 메모리 구조>

buf[4]와 setjmp 에서 저장된 jmp_buf_tag 는 24byte 만큼 떨어져있습니다

정확히 24byte가 OverFlow 되므로 Exploit하는데 문제는 없어 보이는군요

정리해보죠

Shellcode를 한번 메모 기록에 15byte 씩 집어넣습니다

각 기록시 JMP 13 를 붙여 총 17 byte를 입력합니다

이렇게 잘라서 Shellcode를 삽입하고

마지막으로는 24byte를 OverFlow 시켜서 쉘코드의 초기주소로 점프 합니다

이 때 초기주소는 char buf[4] 가 0x0804AD48 이니까

900만큼 빼줘야겠죠 16진수로 384니까 이를 빼주면 0x804A9C0 입니다.

여기서 Memo : 수식부분 앞 꼬리 7 byte 를 건너 뛰면

0x804A9C7 이 됩니다


이를 이용해 vnsecurity 에서 짠 Exploit 코드는 다음과 같습니다



'WarGame' 카테고리의 다른 글

Padocon 2011 Twit Bot 문제 풀이  (0) 2011.02.27
Hackjam level3 Solution - Game of life  (0) 2010.08.28
ISEC 2009 Challenge 12 Solution  (0) 2010.08.23
ISEC 2009 Challenge6 with GOT OverWrite  (0) 2010.08.22
[ CodeGate 2010 ] Challlenge 15 풀이  (0) 2010.07.06
[ CodeGate 2010 ] Challenge 8  (0) 2010.06.22
Posted by LinkC

2010.08.22 00:08 WarGame

*이 풀이는 Vnsecurity 에 올라온 ISEC 2009 Challenge6 풀이를 제 나름대로 정리하여 포스팅한 글임을 알립니다

ISEC 2010 일정이 최근에 공개 되었습니다

지난해 ISEC에 참여는 못했지만 CTF 풀이 문서는 남아 있을 것 같아서

뒤적 거렸더니 풀이 문서는 발견할 수 있었습니다

아쉽게도 문제 링크는 다 죽었더군요 -.-

풀이중에 GOT를 Overwrite 해서 그것도 꽤 특이한 방법을 쓴 것이 있어서

정리하여 둡니다

6번 문제는 Remote BOF 문제라고 합니다

핵심이 되는 주요 함수는 다음과 같습니다



23번째 줄에 있는 strcpy가 첫번째 관문입니다

이후에 있는 34번째 줄의 strncmp의 조건을 만족하기 위해서 이를 활용해야겠죠

randbuf 는 이후로 memset에 의해 초기화가 되니 이를 손댈수는 없고

randnum을 손대야 합니다

buf128에서 32byte를 입력받고

16byte의 destbuf16에 strcpy를 하니까 16byte가 Overflow 됩니다

여기서 randnum을 수정해줘야 하는데

소스상으로 약간 잘못된거 같네요

풀이자가 hand ray 로 풀어낸 모양입니다

아무튼 , 사실 randnum이 destbuf16보다 먼저 선언 되어 있어서

덮어쓸수 있다는 거죠

Dummy byte를 포함해서 쭉 덮어씌워야 합니다

속편하게 32byte 쭉 채워주면 되겠죠

첫번째 입력은 32byte만큼 특정 값을 채워줍니다

그 다음에 32번째에서 다시한번 입력을 받는데요

이번엔 128byte만큼 받습니다

바로 이곳이 Core 라는 겁니다

strncmp로 조금 전에 넣어두었던 randnum에 일치하는 수를 넣어줍니다

예를 들어 A로 채워주었다면

buf128에도 A를 채워넣어주면 되겠죠

는 풰이크고 사실 25번째 줄

snprintf(randbuf12, 5, "%d", randnum)

 에서 5자리만큼 잘려들어갔기 때문에

16337 이 들어갔을 겁니다

사실 randnum 에는 AAAA가 들어갔다고 했을 때 , 1633771873 이라는 값이 들어갔을 것이고

이는 int형의 MAX 값. 2^31-1 = 2147483647 을 넘지 않기 때문에 고스란히 들어갔겠죠

여기서 5자리가 잘려서 16337이 됩니다

또 34번째

if ( strncmp(buf128, randbuf12, 4) ) 

 에서 앞 4자리만 비교를 하게 되니

1633만 넣어주면 되겠죠

처음 4byte 는 1633 입니다

그 다음이 문젠데요

키를 읽어놓고 정작 출력을 해주지 않습니다

황당하기 그지 없는 경우죠

여기서 주목해야 할 점은 printf문 앞의 두 strcpy 문입니다

  strcpy(randbuf12, buf128);  
  strcpy(buf_ptr, buf128);

괜히 집어 넣은게 아니겠죠

buf_ptr이 가리키는게 없던것도 걸립니다

두번째에는 buf_ptr의 값을 맘대로 변경할 수 있게 했구요

네, 그러니까 buf_ptr는 '어디든지 문'이라고 보시면 됩니다

마법의 포인터죠

buf_ptr가 가리키고자 하는 곳의 주소를 입력하면

그 후의 strcpy에서 그 값을 바꿀수 있게 합니다

정말 멋집니다

이제 뭘 해야 할까요?


....




Local 이라면 이것저것 해보겠는데 Remote 라는게 뭐 어쩔 수가 없네요

Printf 문의 "eldhkcalb"  문자열을 keystr 의 주소를 바꾸면 되..

지 않겠네요

포인터로 가리키고 있다면 keystr를 가리키도록 바꾸면 될텐데 직접 문자열로 접근하고 있습니다

주소를 알아봤자 말짱 헛것이라는 거죠

생각해보니 우리가 원하는 것은 printf 문도 아닙니다

그렇다면 소켓으로 keystr을 보내주는 sendsocket 함수를 짜서 보내야될텐데

남은 버퍼에 그것이 다 들어가지도 않을 것이고 , Return Address를 손 댈 상황도 아니며

정확한 Buffer의 주소도 알 수 없습니다






정신을 추스리고 다시 살펴보죠

printf 문의 호출을 다른 함수로 바꿀수 있다면?

Windows의 Hooking 떠오릅니다

여기서 접근 한 것이 GOT 입니다

Global Offset Table의 줄임말로 함수의 정보를 담고 있는 Table 인데요

Windows에서 따지자면 IAT와 같은 역할을 하고 있다고 보시면 됩니다

흡사 Windows 에서 Hooking 하듯이 Linux에 적용해보는 겁니다

다만, 이 경우는 코드의 자유도는 떨어집니다

전에 있던 코드들을 짜깁기 해야만 하죠

흡사 ROP의 개념을 보는 것 같군요

Binary 가 없어서 직접 캡처해서 찍을수 없어 풀이자의 자료를 첨부합니다

<그림1. printf 와 fread의 GOT>

우리의 목적을 먼저 정의해봅시다

sendtosocket(fd , keystr, 32) 함수를 호출 하는 것입니다

이는 fread( keystr, 32, 1 , stream) 과 sendsocket( fd , "~~" );

로 합성될 수 있습니다


마침 인자 순서도 적절하군요

그림1을 보시고 뭔가 감이 오시나요?

printf 문을 호출 할 때 fread의 함수 일부를 호출 - fread를 호출할 때 sendsocket의 일부를 호출

이렇게 연쇄적으로 호출하면 우리가 원하는 목적을 달성할 수 있습니다

이런 류의 문제를 본적이 없어서 이해하는데 꽤 걸려버렸습니다




이를 토대로 Exploit 코드를 짜봅시다

처음 입력 받을 때 a 등의 문자로 32 byte 입력합니다

두번째 입력을 받을 때는 초기 4byte는 첫번째에 넣어주었던 값을 고려해서 strncmp를 통과할 수 있도록 넣어줍니다

이후 code가 핵심인데요

1) buf_ptr 가 우리가 원하는 값을 가리킬수 있도록 dummy byte를 넣어줍니다

<그림2. buf_ptr 하위의 메모리 구조>
* buf_ptr의 값은 아직 미정

2) dummy byte에는 printf의 GOT를 덮어씌울 주소가 들어갑니다

GOT 구조에 따라 이 dummy byte의 구성이 달라집니다

문제 풀이를 보니

0x0804A2FC : waitpid GOT
0x0804A304 : fread GOT
.....
0x0804A316 : printf GOT

이런 식으로 구성이 되어 있는것 같습니다

초기 4byte 때문에 fread 전에 있던 어떤 함수의 GOT부터 수정해 나가야 합니다

그게 바로 waitpid 로군요

이를 토대로 짜보면..

<그림3. Exploit 을 위한 메모리 구조, 변경 전>

그림1 을 참고 했을 때, printf 에는 fread의 일부가

fread 는 sendtosocket이 들어갑니다

<그림3. Exploit 을 위한 메모리 구조, 변경 후>

이를 토대로 짠 Exploit Code 입니다



** 제 나름대로 이해한 방법으로 글을 풀어보았습니다만, 제가 이해를 잘못했다거나 풀이자의 의도를 오해했을 수 있습니다

뭔가 틀린것 같다면 댓글로 남겨주세요 시정하겠습니다 :D
Posted by LinkC

2010.07.06 18:59 WarGame

이 분야 문제는 바이너리로 남아있는 것도 아니고 삽질하면서 풀어보기도 불가능하네요

혼자 삽질해도 풀수 있을지 없을지도 의문이지만..

대회 끝나고 문제소스 등을 공개해주신다면 공부하는데 한결 수월할 것 같은데 말이죠

이번 문제 또한 자력으로 푼게 아니라 , 다른 사이트에 올라온 풀이를 보고 

제가  나름대로 정리하여 올렸음을 알립니다

갈수록 주인장의 잉여력이 묻어나는 군요

또한, 그림은 Wiki 와

http://netifera.com/research/flickr_api_signature_forgery.pdf

 에서 퍼왔음을 명시합니다

이러한 문제를 풀때마다 느끼는 거지만 정말 보안 분야는 넓네요

너무나 다양한 방법이 있고, 그 방법 마저 지속적으로 갱신되고 있으니까요


각설하고, 문제 풀이 들어갑니다

이번 문제는 8번 문제와 비슷합니다

input 값을 주면 그에 해당하는 Cookie 가 생성되고

이 Cookie 를 토대로 웹페이지에서 복호화하여 답인지 아닌지 체크 하는 형식이죠

input 에 aaaa를 넣는다면 다음과 같은 Cookie 가 생성됩니다

web1_auth = YWFhYXwx|8f5c14cc7c1cd461f35b190af57927d1c377997e


그리고 “Welcome back, aaaa! You are not the administrator.”

와 같은 메시지가 출력되죠

Cookie 는 | 를 기준으로 두 파트로 나눌수 있는데

첫번째 파트는 aaaa|1의 Base64 encoding 결과 입니다

두번째는 input 값에 길이가 달라지지도 않고

구성 문자 형식으로 볼때 hash 값이라는 것을 예측할 수 있습니다

길이가 40 이라는 것으로 sha1 으로 좁힐 수 있습니다

sha1 이나 md5 모두 Padding Attack  다른 용어로 length-extention Attack 에 취약합니다

이를 설명하자면.. Key 값인 m\, 자체를 몰라도   h(m)\, 과  len(m)\,  이 주어진다면

h (m||m')\,  을 알아낼 수 있다는 것입니다
 
|| 는 그냥 문자열의 연속이라고 보시면 되구요

이때 padding , extention 은 이 암호화 연산이 Block 단위로 이루어지기 때문에 마지막 Block 을 채워 넣는다고 하는데서

유래된걸로 보입니다

이를 나타내면 다음과 같겠죠




Sha1 의 Block Size는 512bit , 그러니까 64byte가 되겠죠



이를 시험해봅시다

위 참조 사이트에 있는 소스를 긁어서 보겠습니다



이때 필요한 sha1 hash를 수행하는 파일은


수행해보시면 아실수 있겠지만

orig_msg 의 길이는 25 이고

extention 이 적용된 msg 의 길이는 55 인것을 알 수 있습니다

여기에 key 의 길이 9를 합하면 64byte죠

즉 한 Block 을 채운것을 볼 수 있습니다





즉 extension 한 뒤에

add 함수를 이용하여 update 를 호출함으로써

새로 블럭을 생성하여 완성한다는 것입니다

물론 sha1, md5 등의 함수는 길이가 고정되어 있기 때문에

단순히 생성된 블럭을 이어 붙인다는게 아니라

완전히 다른 값이 생성되게 됩니다

아무튼 이렇게 생성을 하게 되면

key값을 모르더라도 key+orig_msg+padding+new_msg 의 Hash 함수를 구할 수 있게 되죠

인증 방식이 <name> | <role> 이기 때문에 가능한 방식입니다

만약 <role> | <name> 이었다면 이 공격 방식은 성공하지 않았겠죠


입력값으로 aaaa를  넣은 cookie 를 이용한다고 했을때

여기서 우리가 입력할 name 은  'aaaa|1'+<paddingggggggg>+'|0' 인 것입니다

|0 까지를 입력한 name 으로 인식하게 하려는 것이죠

실제로 나온 base64 Encoding 값인

YWFhYXwxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4fDA= 

을 decoding 시켜보면  

 aaaa|1€                               ?0

가 나오게 됩니다

이렇게 나온 Signal 값인  70f8bf57aa6d7faaa70ef17e763ef2578cb8d839 을 넣으면

인증을 통과하게 됩니다

재밌지 않나요? :D

'WarGame' 카테고리의 다른 글

ISEC 2009 Challenge 12 Solution  (0) 2010.08.23
ISEC 2009 Challenge6 with GOT OverWrite  (0) 2010.08.22
[ CodeGate 2010 ] Challlenge 15 풀이  (0) 2010.07.06
[ CodeGate 2010 ] Challenge 8  (0) 2010.06.22
[ CodeGate 2010 ] Challenge 7 풀이  (2) 2010.06.21
[ Python Challenge ] level 15  (0) 2010.06.08
Posted by LinkC

2010.06.22 18:50 WarGame


요즘 암호화 문제가 눈에 많이 띄네요

글쓴이의 얕은 지식으로는 못푸는 문제가 산더미같이 많군요

게다가 이번 문제는 바이너리가 아니라 웹 기반의 암호화 문제라 나중에 풀어보는 저로써는

답답하기만 했는데 , 이참에 8번 문제 풀이를 보고 정리하여 포스팅 합니다

참조한 풀이는


입니다

문제는 굉장히 심플했던 걸로 기억합니다

이 문제와 다른 한문제가 비슷한 유형이었던걸로 기억하는데요

아이디를 입력하고 로그인을 누르면 , 일정한 방법으로 쿠키가 생성되고

해당 페이지에서는 그 쿠키를 복호화 하여 로그인한 유저가 admin 인지 아닌지를 가려냅니다

이 쿠키값을 받은 페이지의 출력 결과는

Welcome back, <input>! Your role is: user.

입니다.

문제의 핵심은 쿠키가 어떤 방식으로 생성되는냐 

이겠죠

대략적인 쿠키의 모습은 다음과 같습니다

web4_auth=1vf2EJ15hKzkIxqB27w0AA==|5X5A0e3r48gXhUXZHEKBa5dpC+Xfd\

== 만 보고도 바로 base64 라는 생각이 듭니다

뒤 숫자 모두 base64 범위내의 문자로군요

일단 복호화 시켜보면 알 수 없는 문자만이 난무합니다

중간에 한번더 암호화 되었다는거겠죠

여기서, 문제 풀이 전에 주어진 힌트를 살펴보자면..

the first part is just an IV“.


IV. 로마숫자로 4를 의미하고 정맥의.. 뭐 이런 저런 뜻을 가지고 있는데

우리가 원하는 의미와는 좀 어긋난거 같네요

좀더 좁혀보고자.. IV crypto  라고 구글링을 해보면

뭔가 제대로 짚은거 같네요

In cryptography, an initialization vector (IV) is a block of bits that is required to allow a stream cipher or a block cipher to be executed in any of several modes of operation to produce a unique stream independent from other streams produced by the same encryption key, without having to go through a (usually lengthy) re-keying process

Block cipher 에서 사용되는 초기화 벡터를 나타내는 것이었군요

Block cipher 의 경우 저번에 포스팅 했었죠

그중에서 IV를 사용하는 방식을 살펴보자면..

CBC, CFB 등 여러가지가 있네요

웹 페이지에서 받아오는 쿠키를 base64 decoding 하는 함수와

그 쿠키를 다시 encoding 시켜서 보내주고 그 결과 값을 얻어오는 함수로 나눌 수 있겠죠

vnsec 은  다음과 같이 함수를 짰네요


이제 쿠키가 어떤 방식으로 이루어졌는지 알아봐야 합니다

Block cipher 니까 길이에 따라 결과 값의 길이 역시 달라지겠죠

어디부터 달라지는지 아는가가 목적입니다

길이를 하나씩 늘려서 getcookie 함수를 호출하면


길이 12는 2block . 13은 3block 입니다

1block 당 16byte 니까

2block 은 32byte죠 

32 - 12 = 20 

약 20 바이트가 입력값 외의 데이터죠

분명 role 이 user라는 데이터도 들어가있겠고

username 임을 표시하는 값도 있을 것입니다

어느 분기점 이후로 role 값이 들어가있을 것이고

그 특정 분기점을 나누는 부분에서는 취약점이 있을 것입니다

php 의 대표적인 문자열 취약점이라고 한다면

Null byte 취약점이 있겠죠

이를 이용해서 대입해보면..


빙고네요

대략 쿠키의 구성은

username=<input>##role=user 

그런데 input 에는 ##role에 대한 필터링이 있는 모양이군요

우리가 인식시키고자 하는 것은 ##role=admin 인데 이게 안된다면

입력 후에 값을 변조시켜서 우회를 해야 할 것입니다

여기서 활용되는 개념이


입니다. 

cipher text를 조작시켜 원하는 plain text를 얻는 기법인데요

여기서 주의 해야 할 점은 Block Cipher 의 특징입니다

Block Cipher 는  1 Block 앞의 Cipher Text 와 Decryption  된 Text  간의 

연산이 추가됩니다

이는  바로 Xor 연산인데, Xor 의 성질을 살펴보면

다음과 같이 결합법칙이 성립하는 것을 볼 수 있습니다

(A \otimes B) \otimes C = A \otimes (B \otimes C)

그러니까 Decryption 된 Text 에 Xor 연산을 하는 앞선 Block 의 Cipher Text 에 Xor 를 하는 것은

Decryption 된 Text에 Xor 연산을 하는 것과 동일한 결과를 가져오게 됩니다

또한, 이를 위해서는 조작하고자 하는 Block 앞에 다른 Block 이 있어야겠죠

Username 이 들어가는 첫번째 Block 을 조작했다간 제대로 된 결과를 낼 수 없을 것이기 때문입니다

두번째 Block 을 조작해서 우리가 원하는 3번째 Block 의 값을 바꿔야 합니다

즉..


이런식으로 이루어지겠죠?

3은 16진수로 33

#은 16진수로 23입니다

33  XOR 10 = 23

이므로 7을 10과 XOR 시키면 Decryption 하는 과정에서 #으로 바뀌게 되고

##ROLE 이 완성되면서 admin 으로 인식하게 되는 겁니다

이를 구현하면..


...

배울게 정말 너무 많군요

직접 이 문제를 마주쳤다면 삽질은 삽질대로 하고 못풀었을거 같네요

씁쓸합니다









'WarGame' 카테고리의 다른 글

ISEC 2009 Challenge6 with GOT OverWrite  (0) 2010.08.22
[ CodeGate 2010 ] Challlenge 15 풀이  (0) 2010.07.06
[ CodeGate 2010 ] Challenge 8  (0) 2010.06.22
[ CodeGate 2010 ] Challenge 7 풀이  (2) 2010.06.21
[ Python Challenge ] level 15  (0) 2010.06.08
[ CodeEnge Malware Analysis ] level 8  (0) 2010.05.30
Posted by LinkC

2010.06.21 18:47 WarGame

http://www.vnsecurity.net/2010/03/codegate-2010-challenge7-weak-ssl-cracking/


*이 풀이는 위 두 사이트에서 참조하여 정리하였음을 알려드립니다 




문제의 패킷을 열어보면 , 192.168.100.2 와 192.168.100.4 간의 SSL 통신이 있었음을 알 수 있습니다

패킷의 상세 정보를 보면 RSA 로 암호화 되어 있는 것을 볼 수 있죠

RSA는 대표적인 공개키 알고리즘으로 공개키와 개인키가 모두 있어야만 받은 데이터를 해석 할 수 있습니다



RSA에도 여러 버전이 있는데, 그 버전을 알아야 풀이가 가능하겠죠

지난 번에 포스팅 했던 글에서 공개키의 생성 부분을 잠시 다시 살펴보겠습니다
 
[+] 키의 생성

  1. p \,와 q \, 라고 하는 두 개의 서로 다른 (p \ne q소수를 고른다.
  2. 두 수를 곱하여 N = p q \, 을 찾는다.
  3. \varphi(N) = (p-1)(q-1) \, 를 구한다.
  4. \varphi(N) 보단 작고, \varphi(N)와 서로 소인 정수 를 찾는다.
  5. 유클리드 호제법을 이용하여 d e \equiv 1 \pmod{\varphi(N)} 을 만족시키는 를 구한다.

A의 공개키는 위에서 구한 두 개의 숫자로 이루어진 <Ne>이고, 개인키는 이다. A는 <Ne>만을 B에게 공개하고, B는 이 공개키를 사용하여 자신의 메시지를 암호화하게 된다. 여기서 와 의 보안은 매우 중요하다. 이를 가지고 와 의 계산이 가능하기 때문이다. 그리하여 공개키와 개인키가 생성이 된 후에는 이 두 숫자를 지워버리는 것이 안전하다.



p와 q의 보안은 매우 중요하다고 하였으나

상당 수의 RSA는 p와 q 값이 공개된 상태입니다. 물론 자의적으로 공개한건 아니고

타의적으로 공개되었겠죠 :D



아무튼, p와 q 값을 알기 위해서는 N 값을 알아내서 버전에 맞는 RSA 를 찾아내야 합니다

혹은 패킷에서 추출한 파일을 openssl 로 분석하는 방법이 있겠는데요

Python 코드를 통해 추출하도록 하겠습니다



도출한 N과 e 값을 통해서 p,q 값을 찾습니다

RSA-768 이군요

p , q 값에 확장된 유클리드 호제법을 적용합니다

값이 음수로 나오지만 조건

 d e \equiv 1 \pmod{\varphi(N)} 는 만족하는 것을 확인 하실수 있습니다

이를 통해서, ,개인키 정보를 담은 파일을 만들수 있는데요


이 개인키 파일을 이용해서 ssl 이 적용된 패킷의 정보를 복호화할 수 있습니다



WireShark 를 이용해서 복호화 시켜보면..



쨘-

공개키 구조를 사용한다고 무조건 안전한게 아니군요

하긴 n 값에서 p, q 값을 찾아내리라고 생각지도 못했을 것 같은데 말이죠

이렇게 값이 밝혀진 것을 factor 되었다고 표현하더라구요

RSA 768 같은 경우는 2009년 12월에 factor 되었고..

현재 뚫리지 않은 것 역시 언젠가는 factor 되겠죠

정말이지 보안 분야는 창과 방패의 끝없는 대결같군요 :D

'WarGame' 카테고리의 다른 글

[ CodeGate 2010 ] Challlenge 15 풀이  (0) 2010.07.06
[ CodeGate 2010 ] Challenge 8  (0) 2010.06.22
[ CodeGate 2010 ] Challenge 7 풀이  (2) 2010.06.21
[ Python Challenge ] level 15  (0) 2010.06.08
[ CodeEnge Malware Analysis ] level 8  (0) 2010.05.30
[ CodeEnge Malware Analysis ] level7  (0) 2010.05.30
Posted by LinkC

2010.06.08 09:42 WarGame



지난 문제를 풀고 15번에 입성하면

고양이 들이 반겨줍니다

이름은 uzi 라는데

저 사진에 뭔가 있는지 알았지만 풰이크였습니다

uzi.html 로 들어가면



달력이 나오고

1월 26일에 체크가 되어있군요

whom? 이라는 제목으로 봤을때

이 날짜를 가지고 특정 인물을 유추 해야 한다는 것을 알 수 있습니다

몇년도 인지 알아내는 것이 이 문제의 핵심이겠죠

1 ** 6년 1월 26일 월요일

자세히 보시면 단서가 하나 더 있습니다

우측 하단에 보시면 12월, 2월을 보실 수 있는데요

2월을 보시면 윤년 인것을 알 수 있습니다

이를 토대로 소스를 짜보시면..




5개가 나오는군요

페이지의 소스보기를 하면.. 다음과 같은 힌트를 추가적으로 얻으실 수 있습니다




내일 꽃을 사야된다는군요

그럼 우리가 찾아야 할 날짜는 1월 27일이 되겠죠



이분입니다 :D



'WarGame' 카테고리의 다른 글

[ CodeGate 2010 ] Challenge 8  (0) 2010.06.22
[ CodeGate 2010 ] Challenge 7 풀이  (2) 2010.06.21
[ Python Challenge ] level 15  (0) 2010.06.08
[ CodeEnge Malware Analysis ] level 8  (0) 2010.05.30
[ CodeEnge Malware Analysis ] level7  (0) 2010.05.30
[ CodeEngn Malware Analysis ] level6  (0) 2010.05.30
Posted by LinkC
이전버튼 1 2 3 4 5 이전버튼

블로그 이미지
LinkC

태그목록

Tistory Cumulus Flash tag cloud by BLUEnLIVE requires Flash Player 9 or better.

공지사항

Yesterday49
Today14
Total323,948

달력

 « |  » 2018.12
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          

최근에 받은 트랙백

글 보관함


. .