Haunted Mirror
Challenge:
We found a script being used by DEADFACE. One of our informants says that the code contains one of mort1cia's passwords. There must be a way to get it out of the file.
Solution:
The provided Zip file contained an ELF binary:
$ file mirror
mirror: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, no section header
When run, the program would simply output the argument passed at the command line, but reversed:
$ ./mirror PingTrip
Hello, stranger. I'm trapped behind your screen. Type any word and I'll write it back to you from the other side. Say the right word, and I'll tell you a secret.
PingTrip
pirTgniP
An interesting behavior I noticed is that the program crashed (SIGSEGV) if a command line argument wasn't included. I'll circle back to that later.
Running strings
against the binary produced a portion of the flag, flag{ but not much else of in the way of readable strings. I did notice the binary was UPX packed, which would explain the lack of readable strings:
$ strings mirror | head -n1
UPX!
Luckily, UPX is trivial to unpack:
$ upx -d mirror
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2018
UPX 3.95 Markus Oberhumer, Laszlo Molnar & John Reiser Aug 26th 2018
File size Ratio Format Name
-------------------- ------ ----------- -----------
768464 <- 303916 39.55% linux/amd64 mirror
Circling back to the SIGSEGV
behavior, I loaded the binary into Ghidra to determine what might be causing the error, and spotted the same "flag{" string I observed in the strings
output earlier.
undefined8 main(undefined8 param_1,long param_2)
{
long lVar1;
int local_c;
lVar1 = *(long *)(param_2 + 8);
puts(
"Hello, stranger. I\'m trapped behind your screen. Type any word and I\'ll write it back toyou from the other side. Say the right word, and I\'ll tell you a secret."
);
printf(*(char **)(param_2 + 8),"flag{","XQwG1PhUqJ9A&5v",&DAT_0047f0ba);
putchar(10);
local_c = thunk_FUN_004010d6();
while (local_c = local_c + -1, -1 < local_c) {
putchar((int)*(char *)(lVar1 + local_c));
}
putchar(10);
return 0;
}
The printf
statement caught my eye since it appeared to be the flag being assembled from three parts:
"flag{","XQwG1PhUqJ9A&5v",&DAT_0047f0ba);
I looked for the data segment referenced as the third section and saw that it was a closing bracket:
`0047f0ba 7d ?? 7Dh }`
The completed flag was, flag{XQwG1PhUqJ9A&5v}
Note: After poking at the binary further I realized a simper solution was to leverage a Format String attack. Passing %s%s%s as an argument results in the completed flag being read from process memory and outputted:
$ ./mirror %s%s%s
Hello, stranger. I'm trapped behind your screen. Type any word and I'll write it back to you from the other side. Say the right word, and I'll tell you a secret.
flag{XQwG1PhUqJ9A&5v}
s%s%s%
Leave a comment