The-FLARE-On-Challenge-01/Challenge-6

From aldeid
Jump to navigation Jump to search
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
Note
"bad" could mean that the arguments are incorrect?

And with 3 or more arguments, the program returns "stahp":

$ ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 arg3
stahp
$ ./e7bc5d2c0cf4480348f5504196561297 arg1 arg2 arg3 arg4
stahp
Note
A search on Google about the word "stahp" led me to http://www.internetslang.com/STAHP-meaning-definition.asp. It seems to stand for "STOP".

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 +++
Note
  • 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