Saturday, May 2, 2015

The curious case of crc32 gzinflate php backdoor.

I was working on a side project on an IRH for a certain site. If you got compromised that bad what you should do is ls -lt to find out list of recent files being tampered.

I found out one glaring backdoor which is unlike most php backdoor that I've ever encountered.

















Let's rename it to give it a nicer view..

Summary on how this backdoor works:
  • Malicious data is stored in base64.
  • Upon execution of the script
  • The $data will be decoded from base64
  • Attacker/Controller need to submit a correct $key_value via POST or COOKIE
  • Each byte of  decoded data  in $data_decode  is XOR against ([$key_value + 72670] % 256)
  • $data_decode strings will be reversed and inflate via gzinflate  and assigned to $data_deflate
  • $data_deflate crc32 will be compared agains $data_crc32 to ensure the integrity of the code
  • A full payload function will be created and executed.

Based on experience you can predict that the final output will contain a function call to either exec() , eval(), proc_open() blax33.

There are 3 major challenges in order to  decode the $data properly:

  • Finding the correct keys.
  • Any error in gzinflate()  will trigger an exception and stop the script from executing.
  • Getting the correct crc32 checksum. 
Althought the correct keys is generate from ( $key_value +76270 ) mod 256 , It's possible just to bruteforce for the correct key from 0x00 till 0xFF due to the fact that the payload is xor one byte at a time.

I've tried to decode it back in python. To my disappoinment there is no gzinflate  function in python  but a famous snippet to compensate that is as below:

ungziped_str = zlib.decompressobj().decompress('x\x9c' + gziped_str)
So my watevershit scripting skills .  If I can find the correct key  I should be able to print out the payload.


But will the scripts work as expected ?



TOPKEK haram nye zlib

I'm still figuring out how to be able to inflate the string without triggering an exception . 

Conclusion

The backdoor is duh obviouly a backdoor, It can be detected easily. However implementing a key to the gzinflate value will stop the payload from being executed both by normal user and reverser..


P/S:If anyone can solve this problem it would be nice.

Attached is the link below :

1. Original Code : http://pastebin.com/aLS0NtdZ
2. Label Code :  http://pastebin.com/Gg56vLni
3. Half-Baked Decoder in Python: http://pastebin.com/HzgFmgr1

Btw it's May . Stay tune for WARGAMES 2015.

Updated :

Thanks to Syed Mohd Fadhil  he introduced two way to handle the zlib error .
 Instad of using 'x\x9c'  use guide from php2python  the equivalent for gzinflate in python like php is

zlib.decompress(compressed_data, -15)
And also introduced a nice try and except block to deal with any exception

And Walla we have a nice shell ..


Thanks all for the help

Attached is the full link 

Bruteforce script: http://pastebin.com/AFDJcUpK

Full Web Shell Code : http://pastebin.com/nmgQwTTf