CTF
Search…
STEM CTF: Cyber Challenge 2019
Golang ransomware sucks!

Foreword

After solved re50, i jump directly to re300 because i was re Golang binary once before in root-me.org and pretty confident with it. But, it turns out i was falling to rabbit hole later...and lost 14 hours just fucking around...even though i was got everything in hand at first few hours...

Ransomware

So, basically, the challenges give us two files
One file is encrypted
The other is an ransomware, ELF binary

Stripped Golang Binary

So, first thing first
1
[email protected]:~/Desktop/tmp/stem/re300# file goldfish-ransomware-sample.exe
2
goldfish-ransomware-sample.exe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=K5MarkX6W5LFVyFCqnx1/TP04sI2PJcI7YBPzhARp/65gzfdXiPRtlvJMwzxMx/3eBCF1Fja7XYglCZPIra, stripped
Copied!
So it's stripped binary, which means :
And golang binary contains tons of functions from tons of library, which now we dont even know any of thoses name
So the basic idea now is, we have to identify those functions, which, we have 2 ways to do so :
  • Use tools to BinDiff like diaphora to identify those functions
  • Generate/Find FLIRT database for Golang
But, i dont get lucky with those 2 options, it actually identified some functions, but there are still a lot
Luckily, i found this tool :
1
https://github.com/sibears/IDAGolangHelper
Copied!
Install, run and choose "Rename Functions" :
Result is pretty neat :

Analysis

So, if you havent analyse an golang binary before, then, main() function is in main_main()
So, firstly, the ransomware generate 24 random bytes from an hard coded bytes array and encode it by base64
This base64 string later become your key, which will be submitted to the C&C via POST request
So, i just debug it to get the C&C url :
1
https://docs.google.com/forms/d/e/1FAIpQLSd4VFZA8Cw7ednO-FzLqqesH6wd2z_bxs8-gg6L87kdVvKzkw/formResponse
Copied!
The google forms was closed
So if you was reading blogs about those malwares that use google forms as C&C server, or, played around with google forms a bit, you may know that you just need to change url to :
1
https://docs.google.com/forms/d/e/1FAIpQLSd4VFZA8Cw7ednO-FzLqqesH6wd2z_bxs8-gg6L87kdVvKzkw/viewanalytics
Copied!
To see all requests/analytics
So, we can assume that one of those key is the key that encrypted our file, next we need to find an cipher that was used
The ransomware after sent an key to C&C, it will scan the directory
Where
1
/tmp/safety-folder-18972910363797880709171295166015625
Copied!
But the golang is not terminate string by NULL byte like in C, and there is other string next to our path in memory. So, we need to extract folder name string manually, which turns out to be
1
/tmp/safety-folder-18972910
Copied!
Then it check extension of file
By clicking to a1, we can see something like this
But it's actually an memory address, which is 0x68255b, which is lstat :
And check to see if the file is one of these extensions :
So i just create an folder with some file to test to see if it works

Triple DES - CFB mode

This part actually cost a lot of time...
We can easily realize it use Triple DES - CFB mode to encrypt the file, we have the key, problem is i cannot find where it calculate the IV
So i wrote/got some samples program online, compile it and reverse to understand how things (for, while, slice, array) in golang works. For example
1
https://www.socketloop.com/tutorials/golang-how-to-encrypt-and-decrypt-with-tripledes
Copied!
Me and some friends in @ota was tried but no luck...golang sucks!
This is all in my notes that time
So i was trying to connect the dots, and this idea just pop out
By playing around with some triple des code above, i have an sense that the key will be first 8 chars of key
So i just wrote an quick python script to verify my idea
1
import base64
2
import time
3
f = open('important-file.png.enc')
4
content = f.read()
5
f.close()
6
s = '''d2HwMhfXlRx2Qt/0D92mRwPuHaTdfoy0
7
uC0yC0T45JYqzIL10l4QSVDIkMgeLWaB
8
+ZP4+IqQEz//1AQYrDU3xYYVkyWyQavD
9
n5MHHXyIcAa6Y2OjURoZpDfaOlGp25RF
10
EsxofQlPfvgCqKKQOzKGpsX11x07UC/o
11
PKCcZ5cMFMmB+W4vpHkhTvlFSNs7ufxE
12
vpuZUeG1ZqI0iuKKkRnIrqmM2ODLqbYu
13
N959M+gdQA9dsHR+qNIDJ+mmA9AmqFbE
14
97sh0qzO1rid2gYiEGfpDeAKNlOG6sRI
15
Ubs3cNHDaRSg//TCswkhnjhqyYsxMdUL
16
WI+DDhoCVnYPXzzDZS/mpTM6ZjKbfLl+
17
vQkmDE04cvaWuD+oSSLWqOl+L/P6JcyX
18
FnitjY+xCiUsmcJZFIfju0tJqxxmD8Ix
19
zaIXUY3pwaHEp5S1fyHQEV/+WDgC8qoD
20
a1SUzjT0Xvhb41gCxJvMXLsPclF7Ct8f
21
uDPJrKW4sZytCnfafEqqQG47BRZz1jzZ
22
JLBXCwNSyTWQ6Tw2WIoDnQBF9/y4JRf2
23
07qTl6X7aUkDahq2D0Za4n6DWd2e/7HV
24
ZOhw9d/k0DorBrBPs0d6EfqqO2xOGUeT
25
MFT2qERvcLJsWJFgoR2pfbjhhODrQyYf
26
y4+DZre1CxNhhTXrndBh2c3gfHy7YpV+
27
SGpomDrp+WhcZS/ZxxYER3VA4tQ5J/Pi
28
uCfuOHT+lFarv1S2jxHhIUOvl+ZP6/qc
29
PDbqfb29cuHOhJzC8rLUQO53nKXL/HL6
30
zsJZ3mnW7dV+3MuZn4zUKG8lTxqVabF0
31
8Bq1CmmFsiQQCZStvnsSvMbl9piDV0GQ
32
nmtEKrUIxRi8XdT2CaKHlD2SMsO75gdD
33
hSOx4NXJGxeduIoW86+DbOJn0k6JC8d2
34
y8j/HzFIQczGseJXeSqvM7x5HNU1b8Yj
35
K6tsM0MO5uXGdJpAGmwxz2V/H5x5ZJbv
36
3E37NBoqjgonhk/c7tsOTdprNRyivSvI
37
8jfofO4c4X6ibaOrk8MIi5C4AYQX24qv
38
D4ljQPVcqmX6PBW0wqV84kctKnGUBgs3
39
uhqRguMs9JWMrgDQy9j+8O2DT+QMALt+
40
PCK5TLxPiNv1avoljwNnbabyjLVgDPq1
41
wiMDaHFa2uIACAK4qv/feNfp+ioTXxb4
42
EOj7Z7qVpHQ36keyapnmbDiRp2EPLEgL
43
YJkekhPg0qwSHPeJVVqTrwmukGXt2kjo
44
DumNXMbedc8tz3FHEQYtbTSUmkETsg+3
45
pVYSXDvx9mOZmTfjvXtA3CrVv/LUdx0P
46
6AuGB6RITnkDJZBciVhc0lieNV/2ozNz
47
f4pk+DbN5Iz7UexW8jE8SGuNl2sin97f
48
99vIqrEXgDOf7fSeN8tTTWk6Jk/9g2nA
49
YlvBJwZMNVgIQo0xGE4SG5AMvrqfpJxf
50
6D4amfTmmcFRSkqy7LowkLHYI9r0E/HJ
51
O/dbHUC2QJPCyUlQ7r28P467NakyohcE
52
VeQtgBe0NE6SGBfJfZ6Nvct3+8oDhL+Q
53
YTif2Ye1Ai9gyB8SyzoyNhXsx7dEhFZ/'''
54
55
s = s.split('\n')
56
from Crypto.Cipher import DES3
57
from Crypto import Random
58
59
encrypted_text = base64.b64decode(content)
60
for key in s:
61
key = base64.b64decode(key)
62
iv = key[:8]
63
cipher_decrypt = DES3.new(key, DES3.MODE_CFB, iv) #you can't reuse an object for encrypting or decrypting other data with the same key.
64
output = cipher_decrypt.decrypt(encrypted_text)
65
if output[0] == 'P':
66
print output
67
Copied!
No luck...At that moment, i thought that i was missing something when read code, so next 7-8 hours, i was trying to find the IV in code...but no one got any progress...the Go code is really sucks, flow, calling convention...was too much for my little brain...i was even tried something like :
1
s = 'abc124209eu390wuer' //random shit
2
iv = s[:8]
3
fmt.Println(iv)
Copied!
Even with that simple code, i couldnt find an iv after spend pretty much time on it.
So i was came back with my python script, double check, and i realize that python was fucked up the decryption
More information about that bullshit can be found here
1
https://stackoverflow.com/questions/40004858/encrypt-in-python-and-decrypt-in-java-with-aes-cfb
Copied!

Decryption

So what's next?
Python is not working, so easiest way is to use the language created challenge to solve the challenge
Actually, golang is not that bad, and pretty easy to learn, like python
solver.go
1
package main
2
import "os"
3
import "crypto/cipher"
4
import "crypto/des"
5
//import "encoding/hex"
6
import b64 "encoding/base64"
7
import "fmt"
8
//import "bufio"
9
//import "io"
10
import "io/ioutil"
11
12
13
func main() {
14
b64key := os.Args[1]
15
key, _ := b64.StdEncoding.DecodeString(b64key)
16
d, _ := ioutil.ReadFile(os.Args[2])
17
ciphertext, _ := b64.URLEncoding.DecodeString(string(d))
18
block, err := des.NewTripleDESCipher(key)
19
if err != nil {
20
panic(err)
21
}
22
iv := ciphertext[:8]
23
ciphertext = ciphertext[8:]
24
stream := cipher.NewCFBDecrypter(block, iv)
25
stream.XORKeyStream(ciphertext, ciphertext)
26
fmt.Printf("%s", ciphertext)
27
}
28
Copied!
stimulate.py
1
import os
2
s = '''d2HwMhfXlRx2Qt/0D92mRwPuHaTdfoy0
3
uC0yC0T45JYqzIL10l4QSVDIkMgeLWaB
4
+ZP4+IqQEz//1AQYrDU3xYYVkyWyQavD
5
n5MHHXyIcAa6Y2OjURoZpDfaOlGp25RF
6
EsxofQlPfvgCqKKQOzKGpsX11x07UC/o
7
PKCcZ5cMFMmB+W4vpHkhTvlFSNs7ufxE
8
vpuZUeG1ZqI0iuKKkRnIrqmM2ODLqbYu
9
N959M+gdQA9dsHR+qNIDJ+mmA9AmqFbE
10
97sh0qzO1rid2gYiEGfpDeAKNlOG6sRI
11
Ubs3cNHDaRSg//TCswkhnjhqyYsxMdUL
12
WI+DDhoCVnYPXzzDZS/mpTM6ZjKbfLl+
13
vQkmDE04cvaWuD+oSSLWqOl+L/P6JcyX
14
FnitjY+xCiUsmcJZFIfju0tJqxxmD8Ix
15
zaIXUY3pwaHEp5S1fyHQEV/+WDgC8qoD
16
a1SUzjT0Xvhb41gCxJvMXLsPclF7Ct8f
17
uDPJrKW4sZytCnfafEqqQG47BRZz1jzZ
18
JLBXCwNSyTWQ6Tw2WIoDnQBF9/y4JRf2
19
07qTl6X7aUkDahq2D0Za4n6DWd2e/7HV
20
ZOhw9d/k0DorBrBPs0d6EfqqO2xOGUeT
21
MFT2qERvcLJsWJFgoR2pfbjhhODrQyYf
22
y4+DZre1CxNhhTXrndBh2c3gfHy7YpV+
23
SGpomDrp+WhcZS/ZxxYER3VA4tQ5J/Pi
24
uCfuOHT+lFarv1S2jxHhIUOvl+ZP6/qc
25
PDbqfb29cuHOhJzC8rLUQO53nKXL/HL6
26
zsJZ3mnW7dV+3MuZn4zUKG8lTxqVabF0
27
8Bq1CmmFsiQQCZStvnsSvMbl9piDV0GQ
28
nmtEKrUIxRi8XdT2CaKHlD2SMsO75gdD
29
hSOx4NXJGxeduIoW86+DbOJn0k6JC8d2
30
y8j/HzFIQczGseJXeSqvM7x5HNU1b8Yj
31
K6tsM0MO5uXGdJpAGmwxz2V/H5x5ZJbv
32
3E37NBoqjgonhk/c7tsOTdprNRyivSvI
33
8jfofO4c4X6ibaOrk8MIi5C4AYQX24qv
34
D4ljQPVcqmX6PBW0wqV84kctKnGUBgs3
35
uhqRguMs9JWMrgDQy9j+8O2DT+QMALt+
36
PCK5TLxPiNv1avoljwNnbabyjLVgDPq1
37
wiMDaHFa2uIACAK4qv/feNfp+ioTXxb4
38
EOj7Z7qVpHQ36keyapnmbDiRp2EPLEgL
39
YJkekhPg0qwSHPeJVVqTrwmukGXt2kjo
40
DumNXMbedc8tz3FHEQYtbTSUmkETsg+3
41
pVYSXDvx9mOZmTfjvXtA3CrVv/LUdx0P
42
6AuGB6RITnkDJZBciVhc0lieNV/2ozNz
43
f4pk+DbN5Iz7UexW8jE8SGuNl2sin97f
44
99vIqrEXgDOf7fSeN8tTTWk6Jk/9g2nA
45
YlvBJwZMNVgIQo0xGE4SG5AMvrqfpJxf
46
6D4amfTmmcFRSkqy7LowkLHYI9r0E/HJ
47
O/dbHUC2QJPCyUlQ7r28P467NakyohcE
48
VeQtgBe0NE6SGBfJfZ6Nvct3+8oDhL+Q
49
YTif2Ye1Ai9gyB8SyzoyNhXsx7dEhFZ/'''
50
51
s = s.split('\n')
52
count = 0
53
for key in s:
54
os.system("./solver " + key + " secret.enc > out" + str(count) + ".png")
55
count += 1
56
Copied!
And finally we got flag
flag
1
MCA{stop_ransomware_save_cats}
Copied!

Update

DES CFB mode use first block as IV
Last modified 2yr ago