Title: Reversing of chapro.A Date: 2012-12-25 16:38 I was looking for a nice stuff to reverse when [RootBSD][] pointed me to [e022de72cce8129bd5ac8a0675996318][]. I didn't search for more information about it on the net to keep the reversing fun. :::bash $ file e022de72cce8129bd5ac8a0675996318 e022de72cce8129bd5ac8a0675996318: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped Ho, x86-64, really ? Nice ! But stripped. This is expected for a malware. A quick look at the sections shows nothing about a known packer, but reveals some sections that should have been stripped... Was the programmer silly enough to not read strip's man and didn't use the *-s* option ?! Let's check the imports: :::bash $ rabin2 -i e022de72cce8129bd5ac8a0675996318 | cut -d" " -f7 | cut -c6- | sort ap_add_output_filter ap_hook_insert_filter ap_md5 ap_pass_brigade apr_brigade_cleanup apr_brigade_create apr_bucket_alloc apr_bucket_eos_create apr_bucket_free apr_bucket_heap_create apr_bucket_type_eos ap_register_output_filter apr_file_close apr_file_open apr_palloc apr_table_add apr_table_get ap_set_flag_slot ceil close connect __ctype_b_loc __ctype_tolower_loc __ctype_toupper_loc __cxa_finalize fclose fgets fopen __fprintf_chk fread gethostbyname getpwnam gettimeofday __gmon_start__ gmtime inet_ntoa _Jv_RegisterClasses malloc memcpy __memcpy_chk memset open opendir rand read readdir recv remove rts] send snprintf __snprintf_chk socket __sprintf_chk srand __stack_chk_fail strchr strcmp strftime strlen strncpy strspn strstr strtok __strtol_internal time uname __xstat What are all those strange apr_* imports ? The **Great Internet** tells us [Apache Portable Runtime][]. An Apache malware ? Okay, let's go for symbols: :::bash $ rabin2 -s e022de72cce8129bd5ac8a0675996318 | cut -d" " -f8 | cut -c6- | sort _ADD_TO_BLACKLIST _ADD_TO_WAITLIST ARRAY_BAN_LOCAL_IP ARRAY_BAN_PROC ARRAY_BAN_USERAGENT ARRAY_BLACKLIST_URI ARRAY_SE_REFERER ARRAY_SUDOERS ARRAY_TAGS_FOR_INJECT base64decode base64encode C_ARRAY_BAN_LOCAL_IP C_ARRAY_BAN_PROC C_ARRAY_BAN_USERAGENT C_ARRAY_BLACKLIST_URI C_ARRAY_SE_REFERER C_ARRAY_SUDOERS C_ARRAY_TAGS_FOR_INJECT C_CC_HOST C_CC_REQUEST_FORMAT C_CC_URI CC_HOST CC_REQUEST_FORMAT CC_URI chart_proxy_module _CHECK_BLACKLIST _CHECK_BOT_USERAGENT _CHECK_LOCAL_IP _CHECK_PROC _CHECK_RAW_COOKIE _CHECK_REFERER_IS_HOST _CHECK_REFERER_IS_SEO _CHECK_SITE_ADMIN _CHECK_SITE_KERNEL _CHECK_UTMP _CHECK_WAITLIST C_KEY_COOKIE_NAME CLIENT_IP C_LIST_PREF C_MARKER_LEFT C_MARKER_RIGHT C_MODULE_VERSION C_STRING_1 [...] C_STRING_34 C_TMP_DIR explode FILENAME_UPDATING filesize FILTER _fini from_hex _GEN_FILENAME_BLACKLIST GEN_FILENAME_INJECT GEN_FILENAME_SESSION GEN_FILENAME_WAITLIST _init _INJECT_DO _INJECT_LOAD _INJECT_SAVE _INJECT_SKIP _INJECT_UPDATE ip2long _IS_SUDOER KEY_CLIENT KEY_COOKIE_NAME KEY_XOR LIST_PREF MARKER_LEFT MARKER_RIGHT max min MODULE_VERSION ols] rtrim _SESSION_DELETE _SESSION_KEYGEN _SESSION_LOAD _SESSION_SAVE _SET_COOKIE_KEY SIZE_ARRAY_BAN_PROC SIZE_ARRAY_BAN_USERAGENT SIZE_ARRAY_BLACKLIST_URI SIZE_ARRAY_SE_REFERER SIZE_ARRAY_SUDOERS SIZE_ARRAY_TAGS_FOR_INJECT STRING_1 [...] STRING_34 stristr TMP_DIR to_hex urlencode xor_decrypt_string xor_encrypt xor_encrypt_string Looks like an Apache malware ! Since some useragents/uri/referers/locals ip seems to be checked/banned, maybe the malware deliver its "gifts" only to human visitors of the website, and not to bots. What the fuck are xor_* ?! Encrypting with XOR is the same thing as decrypting... Maybe (and hopefully) these are misleading names. Start function ============== :::asm / function: section..text (23) | 0x000041f0 4883ec08 sub rsp, 0x8 | 0x000041f4 488b05e5402000 mov rax, [rip+0x2040e5] | 0x000041fb 4885c0 test rax, rax | 0x000041fe 7402 jz loc.00004202 | 0x00004200 ffd0 call rax | 0x00004202 4883c408 add rsp, 0x8 0x00004206 c3 ret Weird. The trick is that *call rax* is a call to *__gmon_start__*. > The function call_gmon_start initializes the gmon profiling system. > This system is enabled when binaries are compiled with the -pg flag, > and creates output for use with gprof(1) So, we now've got the entrypoint. Dirty hooker ============ Looks like 0x4330 is responsible of the hooking process. If we take a closer look to *_ap_register_output_filter*, we can see that the filter parameter is 0x69d0, which contains a lot of calls to *_xor_decrypt_string*. Ho, look at the name of the variable being pushed into rbx: KEY_XOR. This must be a joke. Decrypting ---------- Gogogadgeto-python ! :::python import sys from itertools import cycle, izip tab = [ {'name':'C_MODULE_VERSION', 'size':10, 'offset':0x892c}, {'name':'C_CC_HOST', 'size':15, 'offset':0x8936}, {'name':'C_CC_URI', 'size':10, 'offset':0x8945}, {'name':'C_CC_REQUEST_FORMAT', 'size':96, 'offset':0x8960}, {'name':'C_MARKER_LEFT', 'size':3, 'offset':0x89c0}, {'name':'C_MARKER_RIGHT', 'size':3, 'offset':0x89c3}, {'name':'C_TMP_DIR', 'size':1, 'offset':0x89c6}, {'name':'C_LIST_PREF', 'size':5, 'offset':0x89ca}, {'name':'C_COOKIE_NAME', 'size':15, 'offset':0x89cf}, {'name':'C_ARRAY_TAGS_FOR_INJECT', 'size':77, 'offset':0x89e0}, {'name':'C_ARRAY_BAN_USERAGENT', 'size':601, 'offset':0x8a40}, {'name':'C_ARRAY_BLACKLIST_URI', 'size':5, 'offset':0x8c99}, {'name':'C_ARRAY_SE_REFERRER', 'size':281, 'offset':0x8ca0}, {'name':'C_ARRAY_SUDOERS', 'size':1, 'offset':0x8db9}, {'name':'C_ARRAY_BAN_PROC', 'size':98, 'offset':0x8dc0}, {'name':'C_ARRAY_BAN_LOCAL_IP', 'size':48, 'offset':0x8e40}, {'name':'C_STRING_1', 'size':12, 'offset':0x8e70}, {'name':'C_STRING_2', 'size':9, 'offset':0x8e7c}, {'name':'C_STRING_3', 'size':1, 'offset':0x8e85}, {'name':'C_STRING_5', 'size':21, 'offset':0x8e90}, {'name':'C_STRING_5', 'size':1, 'offset':0x8ea5}, {'name':'C_STRING_6', 'size':10, 'offset':0x8ea6}, {'name':'C_STRING_7', 'size':6, 'offset':0x8eb0}, {'name':'C_STRING_8', 'size':7, 'offset':0x8eb6}, {'name':'C_STRING_9', 'size':15, 'offset':0x8ebd}, {'name':'C_STRING_10', 'size':9, 'offset':0x8ecc}, {'name':'C_STRING_11', 'size':9, 'offset':0x8ed5}, {'name':'C_STRING_12', 'size':6, 'offset':0x8ede}, {'name':'C_STRING_13', 'size':1, 'offset':0x8ee4}, {'name':'C_STRING_14', 'size':7, 'offset':0x8ee5}, {'name':'C_STRING_15', 'size':6, 'offset':0x8eec}, {'name':'C_STRING_16', 'size':10, 'offset':0x8ef2}, {'name':'C_STRING_17', 'size':7, 'offset':0x8efc}, {'name':'C_STRING_18', 'size':1, 'offset':0x8f03}, {'name':'C_STRING_19', 'size':1, 'offset':0x8f07}, {'name':'C_STRING_20', 'size':3, 'offset':0x8f09}, {'name':'C_STRING_21', 'size':23, 'offset':0x8f10}, {'name':'C_STRING_22', 'size':10, 'offset':0x8f27}, {'name':'C_STRING_23', 'size':24, 'offset':0x8f40}, {'name':'C_STRING_24', 'size':10, 'offset':0x8f58}, {'name':'C_STRING_25', 'size':1, 'offset':0x8f62}, {'name':'C_STRING_26', 'size':1, 'offset':0x8f63}, {'name':'C_STRING_27', 'size':12, 'offset':0x8f65}, {'name':'C_STRING_28', 'size':23, 'offset':0x8f80}, {'name':'C_STRING_29', 'size':21, 'offset':0x8fa0}, {'name':'C_STRING_30', 'size':6, 'offset':0x8fb5}, {'name':'C_STRING_31', 'size':10, 'offset':0x8fbb}, {'name':'C_STRING_32', 'size':13, 'offset':0x8fc5}, {'name':'C_STRING_33', 'size':20, 'offset':0x8fe0}, {'name':'C_STRING_34', 'size':1, 'offset':0x8ff4}, ] if len(sys.argv) != 2: print('Usage: %s chapro.A sample') % sys.argv[0] sys.exit(0) fd = open(sys.argv[1], 'r') #the XOR key is at offset 0x8920 fd.seek(0x8920) key = fd.read(12) for s in tab: fd.seek(s['offset']) data = fd.read(s['size']) decrypted = ''.join(chr(ord(c)^ord(k)) for c,k in izip(data, cycle(key))) clear_text = decrypted.split('x00')[0] print('%s: %s') % (s['name'], clear_text) Result: :::bash C_MODULE_VERSION: 2012.08.07 C_CC_HOST: 178.162.130.105 C_CC_URI: /index.php C_CC_REQUEST_FORMAT: POST %s HTTP/1.1 Host: %s Content-Type: application/x-www-form-urlencoded Content-Length: %i

%s C_MARKER_LEFT: {{{ C_MARKER_RIGHT: }}} C_TMP_DIR: / C_LIST_PREF: sess_ C_COOKIE_NAME: PHP_SESSION_ID= C_ARRAY_TAGS_FOR_INJECT:

C_ARRAY_BAN_USERAGENT: CHROME GOOGLEBOT SLURP YAHOO BING LINUX OPENBSD [...] CURL PHP INDY LIBRARY C_ARRAY_BLACKLIST_URI: ADMIN C_ARRAY_SE_REFERRER: GOOGLE. YAHOO. YANDEX. RAMBLER. [...] VERDEN. C_ARRAY_SUDOERS: r C_ARRAY_BAN_PROC: f7277f6714e4b034216cf6558cc6327b 28878074a3dd19c7361e8a6d3f04fc17 d0415afe195478d4d8c9af205644f070 C_ARRAY_BAN_LOCAL_IP: C_STRING_1: %i %i %i %s C_STRING_2: text/html C_STRING_3: % C_STRING_5: document.write('%s'); C_STRING_5: r C_STRING_6: User-Agent C_STRING_7: %s%.*s C_STRING_8: Referer C_STRING_9: X-Forwarded-For C_STRING_10: Client-IP C_STRING_11: X-Real-IP C_STRING_12: Cookie C_STRING_13: ; C_STRING_14: %s/%s%s C_STRING_15: INJECT C_STRING_16: javascript C_STRING_17: text/js C_STRING_18: j C_STRING_19: C_STRING_20: id= C_STRING_21: %a %d-%b-%Y %H:%M:%S %Z C_STRING_22: Set-Cookie C_STRING_23: %s%i; expires=%s; path=/ C_STRING_24: Set-Cookie C_STRING_25: w C_STRING_26: % C_STRING_27: Request-Hash C_STRING_28: c=1&version=%s&uname=%s C_STRING_29: c=1&version=%s&uname= C_STRING_30: /proc/ C_STRING_31: 0123456789 C_STRING_32: /proc/%s/comm C_STRING_33: /usr/lib/libbdl.so.0 C_STRING_34: U Woo, lots of stuffs here ! But not many interesting ones. We can see that a cookie is set, maybe for statistics, of in order to avoid spamming client. Somme googling on the md5 hashes didn't gave any results, too bad. Maybe anti-viruses names ? Who knows. Ho, looks like we've got the CC's address: 178.162.130.105. A [whois][] tells us Frankfurt, Germany, but lit's down. We'll never know the payloads. Blacklist --------- If the client matches one of the following conditions, its IP is added to the blacklist. 1. Does the client's ip match a logged-on-the-system one (this is my favorite part) 2. Is the url in the /admin folder ? Papier bitte ------------ Some checks are made before delivering the payload: 1. Does the page contains text/html or javascript resource ? 2. Is the useragent the one from a bot ? 3. Is the IP in the blacklist ? 4. Is the IP in the waitlist ? 5. Is the cookie present ? (see below) 6. Is check if some process are running (process's names are hashed, by I guess they are anti-viruses ones) Here, get infected, take a cookie, and sign our gestbook -------------------------------------------------------- Once the *client* has successfully passed all the tests, the malware sends it the payload, sets a cookie on it, and adds its IP to the *waitlist*. The waitlist is misnamed (or my analyses are wrong), it's a sort of blacklist, but for infected clients. This prevent the client from being spammed by the malware. Injection --------- ### Payloads The *inject_update* function is (obviously) responsible of the payload's updating. Nothing funky here, except an ugly (please don't to this) hack: It opens a socket, *fopen* /usr/lib/libbdl.so.0, and use a POST request of this canvas: :::html POST %s HTTP/1.1 Host: %s Content-Type: application/x-www-form-urlencoded Content-Length: %i %s Then the payload is "unpacked" with a base64decode and a XOR. The same mean is used for updating the malware itself. check_UTMP: nice trick ----------------------- This function checks the content of */var/run/utmp*. The manpage says > The utmp file allows one to discover information about who is > currently using the system. There may be more users currently using > the system, because not all programs use utmp logging. Clever ! This allows to blacklist people logged on the machine. Still in construction ? ======================= I think this is a development version of the malware for the following reasons: - Some functions are not implemented, and always returns 1, like check_site_kernel, check_local_ip, ... - The xor_* collection is (hopefully) a private joke - Some functions are not really usefull, like is_sudoer, Misc ==== The presence of a *explode* function may denote the fact that the author is used to php ;) A quick look with the *strings* command tells us that the module name is *mod_chart_proxy.so*. Go check you Apache server ! Conclusion ========== Nothing hardcore, but still entertaining to reverse: it's the first time that I see an Apache malware. It's a clever idea, but not well coded. I was pretty happy to see that [ESET][] found the same stuffs as me, and jealous that they had access to the payload ! Resources ========= - [About apache hooks][] - [Linux x86 Program Start Up][] [RootBSD]: http://www.r00ted.com/ [e022de72cce8129bd5ac8a0675996318]: https://malware.lu/sample/search.html?hash=e022de72cce8129bd5ac8a0675996318%20 [Apache Portable Runtime]: https://apr.apache.org/ [whois]: http://whois.domaintools.com/178.162.130.105 [ESET]: http://blog.eset.com/2012/12/18/malicious-apache-module-used-for-content-injection-linuxchapro-a [About apache hooks]: http://docstore.mik.ua/orelly/weblinux2/apache/ch20_09.htm [Linux x86 Program Start Up]: http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html