The-FLARE-On-Challenge-01/Challenge-6
You are here | Challenge 6
|
Identification
Download the file: http://www.flare-on.com/files/C6.zip and uncompress it using "malware" as the password:
$ 7z x C6.zip 7-Zip [64] 9.20 Copyright (c) 1999-2010 Igor Pavlov 2010-11-18 p7zip Version 9.20 (locale=fr_FR.UTF-8,Utf16=on,HugeFiles=on,1 CPU) Processing archive: C6.zip Extracting e7bc5d2c0cf4480348f5504196561297 Enter password (will not be echoed) : malware Everything is Ok Size: 1221064 Compressed: 484454
Let's make it executable:
$ chmod +x e7bc5d2c0cf4480348f5504196561297
It results with a 64bit ELF:
$ file e7bc5d2c0cf4480348f5504196561297 e7bc5d2c0cf4480348f5504196561297: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=0xa26451c6440ccb470f9cb8cabf8069c01120086c, stripped
- MD5: e7bc5d2c0cf4480348f5504196561297
- SHA1: 7ff95920877af815c4b33da9a4f0c942fe0907d6
- SHA256: 3487e1de75bcb6f2c1425ca4f9b5da8fb66387343bf4a217c5a5cf93c79f0d9d
We have to deal with a 64-bit ELF that is statically linked and without symbols (stripped). IDA-Pro reveals 2300+ functions and 1400+ strings:
Program arguments
Playing with the number of arguments
With no argument, the program returns "no":
$ ./e7bc5d2c0cf4480348f5504196561297 no
With 1 argument, the program returns "na":
$ ./e7bc5d2c0cf4480348f5504196561297 arg1 na
With 2 arguments, the program returns "bad":
$ ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 bad
And with 3 or more arguments, the program returns "stahp":
$ ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 arg3 stahp $ ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 arg3 arg4 stahp
Determine how many arguments the program expects
no
To determine how many arguments the program expects, we can focus on the strings "no", "na", "bad" and "stahp". The "no" string is found at offset 0x4F3FE9 and has only 1 reference, in sub_45079:
As depicted below, the number of arguments (var_A84) is checked. If the number of argument is not 1, the program jumps to loc_4535CA. But if there is only 1 argument, "no" is printed (sub_45EBE0) and the program terminates (sub_45E790).
na
Same story for "na":
stahp
Same story for "stahp" too:
Conclusion
The program is expecting 2 arguments.
sub_4742B0 (offset 0x4742B0), the "ptrace" anti-debugging trick
strace
When using strace:
With no argument:
$ strace -i ./e7bc5d2c0cf4480348f5504196561297 [00007f7869add927] execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"...], [/* 39 vars */]) = 0 [00000000004a9297] uname({sys="Linux", node="unknown", ...}) = 0 [00000000004aa78a] brk(0) = 0x2274000 [00000000004aa78a] brk(0x22751c0) = 0x22751c0 [000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x2274880) = 0 [00000000004aa78a] brk(0x22961c0) = 0x22961c0 [00000000004aa78a] brk(0x2297000) = 0x2297000 [0000000000473e44] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [000000000047509a] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f545afea000 [0000000000473f50] write(1, "no\n", 3no ) = 3 [0000000000473dd8] exit_group(52) = ? [????????????????] +++ exited with 52 +++
With 1 argument:
$ strace -i ./e7bc5d2c0cf4480348f5504196561297 arg1 [00007f57cb771927] execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1"], [/* 39 vars */]) = 0 [00000000004a9297] uname({sys="Linux", node="unknown", ...}) = 0 [00000000004aa78a] brk(0) = 0x10fa000 [00000000004aa78a] brk(0x10fb1c0) = 0x10fb1c0 [000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x10fa880) = 0 [00000000004aa78a] brk(0x111c1c0) = 0x111c1c0 [00000000004aa78a] brk(0x111d000) = 0x111d000 [0000000000473e44] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [000000000047509a] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b6d59a000 [0000000000473f50] write(1, "na\n", 3na ) = 3 [0000000000473dd8] exit_group(423) = ? [????????????????] +++ exited with 167 +++
With 2 arguments:
$ strace -i ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 [00007f3883d8b927] execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1", "arg2"], [/* 39 vars */]) = 0 [00000000004a9297] uname({sys="Linux", node="unknown", ...}) = 0 [00000000004aa78a] brk(0) = 0xdfd000 [00000000004aa78a] brk(0xdfe1c0) = 0xdfe1c0 [000000000045e3f5] arch_prctl(ARCH_SET_FS, 0xdfd880) = 0 [00000000004aa78a] brk(0xe1f1c0) = 0xe1f1c0 [00000000004aa78a] brk(0xe20000) = 0xe20000 [000000000047431b] ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted) [0000000000473e44] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [000000000047509a] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9a0dd45000 [0000000000473f50] write(1, "Program received signal SIGSEGV,"..., 52Program received signal SIGSEGV, Segmentation fault ) = 52 [0000000000473dd8] exit_group(9001) = ? [????????????????] +++ exited with 41 +++
With 3 arguments:
$ strace -i ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 arg3 [00007fe34b164927] execve("./e7bc5d2c0cf4480348f5504196561297", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1", "arg2", "arg3"], [/* 39 vars */]) = 0 [00000000004a9297] uname({sys="Linux", node="unknown", ...}) = 0 [00000000004aa78a] brk(0) = 0x149c000 [00000000004aa78a] brk(0x149d1c0) = 0x149d1c0 [000000000045e3f5] arch_prctl(ARCH_SET_FS, 0x149c880) = 0 [00000000004aa78a] brk(0x14be1c0) = 0x14be1c0 [00000000004aa78a] brk(0x14bf000) = 0x14bf000 [0000000000473e44] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [000000000047509a] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb3bb7bb000 [0000000000473f50] write(1, "stahp\n", 6stahp ) = 6 [0000000000473dd8] exit_group(14) = ? [????????????????] +++ exited with 14 +++
- The system call number is put in the EAX register before syscall is called. For a list of values, you can refer to this link: https://filippo.io/linux-syscall-table/
- strace run with the -s option prints the instruction pointer at the time of the system call, which is very useful to find the code in IDA Pro.
In IDA Pro, we jump to offset 0x000000000047431b since this is the instruction pointer provided by strace at the time of ptrace:
101 (0x65) is moved to EAX before syscall is called. The table indicates it is ptrace:
Source: https://filippo.io/linux-syscall-table/
Patch
Let's get rid of this anti-debugging trick by patching the code. To do that, we will identify where sub_4742B0 is referenced (click on the name of the function and press "x" to display cross references):
We can see that it is called only once in the code, in sub41C77D:
At offset 0x000000000041F21C, we want to replace the conditional jump (jz) with a non-conditional one (jmp). First display the opcodes in IDA Pro (Options > General > Number of opcode bytes: 15) to identify the bytes to patch and refer to http://ref.x86asm.net/coder64.html to get the value of a simple jmp: EB:
$ objdump -d e7bc5d2c0cf4480348f5504196561297.init | grep -B3 -i 41F21C 41f211: e8 9a 50 05 00 callq 0x4742b0 41f216: 48 c1 e8 3f shr $0x3f,%rax 41f21a: 84 c0 test %al,%al 41f21c: 74 14 je 0x41f232 $ objdump -d e7bc5d2c0cf4480348f5504196561297.patched | grep -B3 -i 41F21C 41f211: e8 9a 50 05 00 callq 0x4742b0 41f216: 48 c1 e8 3f shr $0x3f,%rax 41f21a: 84 c0 test %al,%al 41f21c: eb 14 jmp 0x41f232
You can perform this operation either from an Hex editor (e.g. wxHexEditor) or directly from IDA-Pro.
Now, the command is no longer returning a segfault:
$ strace -i ./e7bc5d2c0cf4480348f5504196561297-patched arg1 arg2 [ 7faff5265667] execve("./e7bc5d2c0cf4480348f5504196561297-patched", ["./e7bc5d2c0cf4480348f55041965612"..., "arg1", "arg2"], [/* 17 vars */]) = 0 [ 4a9297] uname({sys="Linux", node="test", ...}) = 0 [ 4aa78a] brk(0) = 0x24c2000 [ 4aa78a] brk(0x24c31c0) = 0x24c31c0 [ 45e3f5] arch_prctl(ARCH_SET_FS, 0x24c2880) = 0 [ 4aa78a] brk(0x24e41c0) = 0x24e41c0 [ 4aa78a] brk(0x24e5000) = 0x24e5000 [ 47431b] ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted) [ 473e44] fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 [ 47509a] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f89233a3000 [ 473f50] write(1, "bad\n", 4bad ) = 4 [ 473dd8] exit_group(420) = ?
From the "bad" string, the first argument
Functions where the "bad" string is referenced
The "bad" string is called 2 times in the program, within the same function (sub_435E20):
sub_435E20 (offset 0x43710C)
The first argument length is 10 (0x0A)
sub_435E20 (offset 0x4371DE)
Using a debugger (e.g. edb), we understand that the string "bngcg`debd" is XOR'ed with 0x56 to obtain the value of the 1st argument.
$ python >>> s = 'bngcg`debd' >>> x = 0x56 >>> ''.join([chr(ord(i) ^ x) for i in s]) '4815162342'
The first argument value is 4815162342.
sub_473D40
nanosleep
Now, if we provide our program with the first argument (4815162342) and an arbitrary second argument, the program does no longer return "bad", but nothing seems to happen.
Let's use strace to understand what happens:
$ strace -i ./e7bc5d2c0cf4480348f5504196561297-patched 4815162342 arg2 [ 7f96e16f7667] execve("./e7bc5d2c0cf4480348f5504196561297-patched", ["./e7bc5d2c0cf4480348f55041965612"..., "4815162342", "arg2"], [/* 30 vars */]) = 0 [ 4a9297] uname({sys="Linux", node="test", ...}) = 0 [ 4aa78a] brk(0) = 0x2379000 [ 4aa78a] brk(0x237a1c0) = 0x237a1c0 [ 45e3f5] arch_prctl(ARCH_SET_FS, 0x2379880) = 0 [ 4aa78a] brk(0x239b1c0) = 0x239b1c0 [ 4aa78a] brk(0x239c000) = 0x239c000 [ 47431b] ptrace(PTRACE_TRACEME, 0, 0x1, 0) = -1 EPERM (Operation not permitted) [ 47c9c0] rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0 [ 47c882] rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0 [ 47c9c0] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 [ 473d50] nanosleep({3600, 0},
We can see a nanosleep at offset 0x473d50. In IDA Pro, we confirm 0x63 (35) is moved to EAX and syscall is then called. Still referring to the syscall table, we confirm it corresponds to "nanosleep".
Patch
We can see that nanosleep is called 2 times in the function. Let's patch the code by replacing syscall with NOP's, as follows:
$ objdump -M intel -d e7bc5d2c0cf4480348f5504196561297.init > init.txt $ objdump -M intel -d e7bc5d2c0cf4480348f5504196561297.patched2 > patched2.txt $ diff init.txt patched2.txt [SNIP] 33325c33325 < 41f21c: 74 14 je 0x41f232 --- > 41f21c: eb 14 jmp 0x41f232 122582,122583c122582,122588 < 473d49: b8 23 00 00 00 mov eax,0x23 < 473d4e: 0f 05 syscall --- > 473d49: 90 nop > 473d4a: 90 nop > 473d4b: 90 nop > 473d4c: 90 nop > 473d4d: 90 nop > 473d4e: 90 nop > 473d4f: 90 nop 122590,122591c122595,122601 < 473d6a: b8 23 00 00 00 mov eax,0x23 < 473d6f: 0f 05 syscall --- > 473d6a: 90 nop > 473d6b: 90 nop > 473d6c: 90 nop > 473d6d: 90 nop > 473d6e: 90 nop > 473d6f: 90 nop > 473d70: 90 nop
Shellcode, the second argument
call rdx at offset 0x44bb2b
As shown below (extract from edb), there is a call rdx instruction at offset 0x44bb2b:
If we put a breakpoint there, run the program (F9) and step in (F7), we arrive at the shellcode that checks the second parameter, letter by letter.
As you can see, for each letter, there are transformations (ror, rol, xor, add, sub) applied to the letter provided. The result is then compared to an expected result. If it succeeds (expected result), the program continues and if it fails, it exits.
Reverse engineering the letters
Explanation
Since we have the result of the transformations for each letter, it is possible to reverse the logic to get the initial letter. Let's take an example (letter 4). The code is as follows:
add byte ptr [rax], 0xa3
ror byte ptr [rax], 0xbc
cmp byte ptr [rax], 0xb0
The logic is depicted on the below diagram:
The code
#!/usr/bin/env python
# source for rol and ror: http://www.falatic.com/index.php/108/python-and-bitwise-rotation
# Rotate left. Set max_bits to 8.
rol = lambda val, r_bits, max_bits=8: \
(val << r_bits%max_bits) & (2**max_bits-1) | \
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits)))
# Rotate right. Set max_bits to 8.
ror = lambda val, r_bits, max_bits=8: \
((val & (2**max_bits-1)) >> r_bits%max_bits) | \
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1))
l = []
### Letter 1
"""
ror byte ptr [rax], 0xf2
cmp byte ptr [rax], 27
"""
l.append( rol(27, 0xf2) )
### Letter 2
"""
xor byte ptr [rax], 64
xor byte ptr [rax], 0xf2
xor byte ptr [rax], 0xb3
cmp byte ptr [rax], 48
"""
l.append( 48 ^ 0xb3 ^ 0xf2 ^ 64 )
### Letter 3
"""
xor byte ptr [rax], 113
cmp byte ptr [rax], 31
"""
l.append( 31 ^ 113 )
### letter 4
"""
add byte ptr [rax], 0xa3
ror byte ptr [rax], 0xbc
cmp byte ptr [rax], 0xb0
"""
l.append( rol(0xb0, 0xbc) - 0xa3 )
### letter 5
"""
sub byte ptr [rax], 121
cmp byte ptr [rax], 0xe8
"""
l.append( 0xe8 + 121 )
### letter 6
"""
ror byte ptr [rax], 0x82
sub byte ptr [rax], 40
cmp byte ptr [rax], 0xf6
"""
l.append( rol(0xf6 + 40, 0x82) )
### letter 7
"""
sub byte ptr [rax], 0xb0
ror byte ptr [rax], 77
add byte ptr [rax], 44
cmp byte ptr [rax], 31
"""
l.append( rol(31 - 44, 77) + 0xb0 )
### letter 8
"""
add byte ptr [rax], 84
rol byte ptr [rax], 0x99
xor byte ptr [rax], 0xb8
ror byte ptr [rax], 42
add byte ptr [rax], 63
cmp byte ptr [rax], 0xaf
"""
l.append( ror(rol(0xaf - 63, 42) ^ 0xb8, 0x99) - 84 )
### letter 9
"""
ror byte ptr [rax], 0xba
cmp byte ptr [rax], 93
"""
l.append( rol(93, 0xba) )
### letter 10
"""
xor byte ptr [rax], 0xed
ror byte ptr [rax], 108
add byte ptr [rax], 48
cmp byte ptr [rax], 41
"""
l.append( rol(41 - 48, 108) ^ 0xed )
### letter 11
"""
sub byte ptr [rax], 0xbf
cmp byte ptr [rax], 0xb5
"""
l.append( 0xb5 + 0xbf )
### letter 12
"""
rol byte ptr [rax], 0xbc
add byte ptr [rax], 0x8c
rol byte ptr [rax], 123
sub byte ptr [rax], 49
add byte ptr [rax], 99
cmp byte prt [rax], 0xa5
"""
l.append( ror(ror(0xa5 - 99 + 49, 123) - 0x8c, 0xbc) )
### letter 13
"""
rol byte ptr [rax], 32
rol byte ptr [rax], 22
xor byte ptr [rax], 0xae
rol byte ptr [rax], 0x98
cmp byte ptr [rax], 0xf3
"""
l.append( ror(ror(ror(0xf3, 0x98) ^ 0xae, 22), 32) )
### letter 14
"""
ror byte ptr [rax], 110
add byte ptr [rax], 0xd2
cmp byte ptr [rax], 0xa6
"""
l.append( rol(0xa6 - 0xd2, 110) )
### letter 15
"""
add byte ptr [rax], 52
cmp byte ptr [rax], 98
"""
l.append( 98 - 52 )
### letter 16
"""
add byte ptr [rax], 0xcd
sub byte ptr [rax], 16
add byte ptr [rax], 98
xor byte ptr [rax], 0xb2
cmp byte ptr [rax], 50
"""
l.append( (50 ^ 0xb2) - 98 + 16 - 0xcd )
### letter 17
"""
xor byte ptr [rax], 0xb7
xor byte ptr [rax], 115
ror byte ptr [rax], 7
cmp byte ptr [rax], 0xeb
"""
l.append( rol(0xeb, 7) ^ 115 ^ 0xb7 )
### letter 18
"""
add byte ptr [rax], 52
sub byte ptr [rax], 97
ror byte ptr [rax], 54
add byte ptr [rax], 91
sub byte ptr [rax], 76
cmp byte ptr [rax], 11
"""
l.append( rol(11 + 76 - 91, 54) + 97 - 52 )
### letter 19
"""
add byte ptr [rax], 90
cmp byte ptr [rax], 0x9a
"""
l.append( 0x9a - 90 )
### letter 20
"""
ror byte ptr [rax], 0xa2
cmp byte ptr [rax], 0x99
"""
l.append( rol(0x99, 0xa2) )
### letter 21
"""
xor byte ptr [rax], 126
sub byte ptr [rax], 0xe7
cmp byte ptr [rax], 43
"""
l.append( (43 + 0xe7) ^ 126 )
### letter 22
"""
sub byte ptr [rax], 0xb8
xor byte ptr [rax], 0x86
add byte ptr [rax], 78
ror byte ptr [rax], 74
rol byte ptr [rax], 87
cmp byte ptr [rax], 0xaf
"""
l.append( ((rol(ror(0xaf, 87), 74) - 78) ^ 0x86) + 0xb8 )
### letter 23
"""
ror byte ptr [rax], 0x86
xor byte ptr [rax], 0xe8
rol byte ptr [rax], 0x95
xor byte ptr [rax], 74
xor byte ptr [rax], 0xad
cmp byte ptr [rax], 0xc3
"""
l.append( rol(ror(0xc3 ^ 0xad ^ 74, 0x95) ^ 0xe8, 0x86) )
### letter 24
"""
ror byte ptr [rax], 69
xor byte ptr [rax], 0xcc
add byte ptr [rax], 28
cmp byte ptr [rax], 3
"""
l.append( rol((3 - 28) ^ 0xcc, 69) )
### letter 25
"""
sub byte ptr [rax], 74
cmp byte ptr [rax], 0xe3
"""
l.append( 0xe3 + 74 )
### letter 26
"""
xor byte ptr [rax], 0xa5
ror byte ptr [rax], 0x90
cmp byte ptr [rax], 0xca
"""
l.append( rol(0xca, 0x90) ^ 0xa5 )
### letter 27
"""
ror byte ptr [rax], 0xde
rol byte ptr [rax], 54
xor byte ptr [rax], 120
sub byte ptr [rax], 0xd8
cmp byte ptr [rax], 62
"""
l.append( rol(ror((62 + 0xd8) ^ 120, 54), 0xde) )
### letter 28
"""
add byte ptr [rax], 0xb5
sub byte ptr [rax], 0xad
ror byte ptr [rax], 0x89
rol byte ptr [rax], 0xa2
rol byte ptr [rax], 17
cmp byte ptr [rax], 0xd8
"""
l.append( rol(ror(ror(0xd8, 17), 0xa2), 0x89) + 0xad - 0xb5 )
### letter 29
"""
add byte ptr [rax], 64
sub byte ptr [rax], 33
ror byte ptr [rax], 0xc0
cmp byte ptr [rax], 0x82
"""
l.append( rol(0x82, 0xc0) + 33 - 64 )
### letter 30
"""
rol byte ptr [rax], 0xe3
cmp byte ptr [rax], 123
"""
l.append( ror(123, 0xe3) )
### letter 31
"""
sub byte ptr [rax], 120
ror byte ptr [rax], 0xf6
cmp byte ptr [rax], 0xd7
"""
l.append( rol(0xd7, 0xf6) + 120 )
# modulo 256 applied to ensure values are in range(256)
print ''.join([chr(i % 256) for i in l])
Solution and program behavior when provided with the 2 correct arguments
Solution
Running the code above outputs:
$ ./decode.py [email protected]
Program behavior when provided with the 2 correct arguments
Now that we know the 2 arguments the program was expecting to work, let's see what happens when we run it with the 2 arguments:
$ ./e7bc5d2c0cf4480348f5504196561297.patched2 4815162342 [email protected] [1]+ Stoppé ./e7bc5d2c0cf4480348f5504196561297.patched2 4815162342 [email protected]
The program runs during 1 minute but nothing is output and then stops. Behind the scenes, it actually connects to an IP (9.30.75.86) belonging to IBM, on port 39426/tcp:
$ whois 9.30.75.86 [SNIP] NetRange: 9.0.0.0 - 9.255.255.255 CIDR: 9.0.0.0/8 NetName: IBM NetHandle: NET-9-0-0-0-1 Parent: () NetType: Direct Assignment OriginAS: Organization: IBM (IBM-1) RegDate: 1988-12-16 Updated: 2011-09-06 Ref: http://whois.arin.net/rest/net/NET-9-0-0-0-1 OrgName: IBM OrgId: IBM-1 Address: 3039 Cornwallis Road City: Research Triangle Park StateProv: NC PostalCode: 27709-2195 Country: US RegDate: 1992-02-08 Updated: 2012-02-03 Ref: http://whois.arin.net/rest/org/IBM-1 OrgAbuseHandle: RAIN-ARIN OrgAbuseName: Registrar Authority, Internet numbers OrgAbusePhone: +1-800-426-7378 OrgAbuseEmail: [email protected] OrgAbuseRef: http://whois.arin.net/rest/poc/RAIN-ARIN OrgTechHandle: RAIN-ARIN OrgTechName: Registrar Authority, Internet numbers OrgTechPhone: +1-800-426-7378 OrgTechEmail: [email protected] OrgTechRef: http://whois.arin.net/rest/poc/RAIN-ARIN [SNIP]
At the time of this writting, the remote host seems down.
Comments
Keywords: reverse-engineering challenge flare fireeye x64 linux elf