practical cpp reversing
Post on 07-Apr-2018
243 Views
Preview:
TRANSCRIPT
-
8/3/2019 Practical Cpp Reversing
1/36
Practical C++ reversing
Benjamin Vanheuverzwijn
ESET
-
8/3/2019 Practical Cpp Reversing
2/36
About me
Employee @ ESET botnet analysis
Student in electrical engineering @ E.T.S. Member @ CISSP groupies
bvanheu@gmail.com
-
8/3/2019 Practical Cpp Reversing
3/36
Win32/Kelihos
scan your harddrive network dump send spam DDoS
2 mb binary packed
custom UPX
multiple libraries Boost winpcap protocol library
(http,...) heavy thread usage P2P protocol
-
8/3/2019 Practical Cpp Reversing
4/36
Objectives
Reverse Kelihos network stack1. raw data handler2. packet handler3. message handler
Learn how C++ works in assembly1. object construction2. call convention3. object layout in memory
Exploit weakness in the Kelihos protocol
-
8/3/2019 Practical Cpp Reversing
5/36
The plan
Infect a machine Kelihos listens on port 80 Hook a debugger Reverse the packet handling stack:
raw data handler packet handler header handler message handler
-
8/3/2019 Practical Cpp Reversing
6/36
First step (1/2)
Static analysis is hard (without context) Finding an entry point (network) Put a breakpoint on WSARecv Send some data
-
8/3/2019 Practical Cpp Reversing
7/36
First step (2/2)
The stack.
-
8/3/2019 Practical Cpp Reversing
8/36
Followed by static analysis
References toWSARecv():deep inboost.asio!
-
8/3/2019 Practical Cpp Reversing
9/36
Object construction
"new(size_t s)" wraps "malloc(size_t s)" Call the constructor function (using "edi" as "memory ptr")
-
8/3/2019 Practical Cpp Reversing
10/36
Compiler paradigm: constructor
call to new(size_t) malloc() memory
call to "base_class->construct()" function that initialize the structure
call to "member->construct()" when object has object members
call to "object->construct()" written by the programmer
returns "this" in eax
-
8/3/2019 Practical Cpp Reversing
11/36
Raw data handler
recv_handler function:
-
8/3/2019 Practical Cpp Reversing
12/36
Raw data handler
From dynamic (debugger) analysis:
-
8/3/2019 Practical Cpp Reversing
13/36
Raw data handler
From WSARecv documentation:"If no error occurs and the receive operation has completedimmediately, WSARecv returns zero."
-
8/3/2019 Practical Cpp Reversing
14/36
Raw data handler
There is still some question: Using ecxwithout initialization? Calling a register initialized with ecx?
-
8/3/2019 Practical Cpp Reversing
15/36
Compiler paradigm: call convention
Register used for "this" ptr (usually ecx) Parameters on the stack Static method: A::static_fct(int x)
push 42 - push parameter
call static_fct - call the static function Classic method: a->fct(int y)
push 42 - push parameter (int z) mov ecx, esi - put "this" in ecx call fct - call the function
Virtual method: a->v_fct(int z) push 42 - push parameter (int z) mov eax, [esi] - dereference vftable mov ecx, esi - put "this" in ecx call [eax] - call the function (vftable)
-
8/3/2019 Practical Cpp Reversing
16/36
Raw data handler
We come from classic method: this->fct(int z) ecxis used without initialization ebxis used to reference "this"
-
8/3/2019 Practical Cpp Reversing
17/36
Raw data handler
But... we still have a question: calling "[this+20C8]+0x4"?
-
8/3/2019 Practical Cpp Reversing
18/36
Compiler paradigm: instance layout
Virtual function table (vft) Members
-
8/3/2019 Practical Cpp Reversing
19/36
Raw data handler
What we know from the instance layout of the object: 1 vftable = 1 parent class vftable are hard to follow in static analysis
-
8/3/2019 Practical Cpp Reversing
20/36
Packet handler
-
8/3/2019 Practical Cpp Reversing
21/36
Packet handler
-
8/3/2019 Practical Cpp Reversing
22/36
Packet handler
-
8/3/2019 Practical Cpp Reversing
23/36
Packet handler
Call to string::append(char *buffer, size_t length) Now we know "member_2" is a String
-
8/3/2019 Practical Cpp Reversing
24/36
Packet handler
-
8/3/2019 Practical Cpp Reversing
25/36
Packet handler
-
8/3/2019 Practical Cpp Reversing
26/36
Packet handler
Call to string::append()1. push parameters2. put the string pointer in "ecx"3. call the function
Call to string::operator[]()1. push parameter2. put the string pointer in "ecx"3. call the function4. eax will now point on the position
We learn that for a valid packet: must not begin with 0x0500 must have a minimum length of 0x08
-
8/3/2019 Practical Cpp Reversing
27/36
Static analysis: header_handler
We then pass trough a lot of not efficient code:1. validate packet headers2. unpack packet headers3. strip headers
4. call the message_handler
-
8/3/2019 Practical Cpp Reversing
28/36
Header validation
-
8/3/2019 Practical Cpp Reversing
29/36
Header unpacking
-
8/3/2019 Practical Cpp Reversing
30/36
Static analysis: header_unpack
1. head1, head2, a and b = random integers2. crypted_size = c - head1 - a3. msg_type = d - crypted_size - 2* (head1 - a)
-
8/3/2019 Practical Cpp Reversing
31/36
Message handler
-
8/3/2019 Practical Cpp Reversing
32/36
Message handler
msg of type "Bootstrap"
-
8/3/2019 Practical Cpp Reversing
33/36
More about kelihos P2P protocol
Payload is: Encrypted Compressed Serialized
Bootstrap message contains: Peerlist Peer information (ip, port, etc)
The bug: port is serialized with 4 bytes cast in 2 bytes needed
-
8/3/2019 Practical Cpp Reversing
34/36
Bootstrap message
Label: m_live_time Type: ValueScalar value:73 size:8
...Label: m_listenning_port Type: Value
Scalar value:80 size:4
Label: m_real_target_ip Type: ValueScalarvalue:62.4.47.49 size:4
Label: m_bootstrap_list Type: Section...
-
8/3/2019 Practical Cpp Reversing
35/36
Inject peers
Peer with high live_time is kept first in the list Peers are identified with ip AND port Inject same ip but with different port (80 dec. = 0x50)
0xAAAA0050 & 0x0000FFFF = 0x50
0xBBBB0050 & 0x0000FFFF = 0x50 Injected peer list:
m_ip = 64.12.41.51m_live_time = 9999999m_listening_port = 0xAAAA0050
...m_ip = 64.12.41.51m_live_time = 9999999m_listening_port = 0xBBBB0050
-
8/3/2019 Practical Cpp Reversing
36/36
Question? / Answer!
top related