Description: My coredump helper is crashing while handling a crash : (
After loading binary in ida pro and decompile main function we see this:
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
unsigned __int64 SP; // rbx
Binary *Binary; // rax
unsigned __int64 NumberOfThreads; // rax
size_t v7; // rbx
const void *v8; // rsi
char v10[32]; // [rsp+10h] [rbp-2B0h] BYREF
char v11[32]; // [rsp+30h] [rbp-290h] BYREF
__int64 v12[4]; // [rsp+50h] [rbp-270h] BYREF
char v13[40]; // [rsp+70h] [rbp-250h] BYREF
char v14[8]; // [rsp+98h] [rbp-228h] BYREF
char v15[32]; // [rsp+A0h] [rbp-220h] BYREF
char v16[368]; // [rsp+C0h] [rbp-200h] BYREF
char v17[40]; // [rsp+230h] [rbp-90h] BYREF
__int64 MappedAddress; // [rsp+258h] [rbp-68h] BYREF
unsigned __int64 FrameCount; // [rsp+260h] [rbp-60h]
__int64 MappedRegisterSet; // [rsp+268h] [rbp-58h]
Backtrace *Backtrace; // [rsp+270h] [rbp-50h]
unsigned int i; // [rsp+27Ch] [rbp-44h]
__int64 v23; // [rsp+280h] [rbp-40h]
void *s; // [rsp+288h] [rbp-38h]
unsigned __int64 k; // [rsp+290h] [rbp-30h]
unsigned __int64 j; // [rsp+298h] [rbp-28h]
void *buf; // [rsp+2A0h] [rbp-20h]
size_t size; // [rsp+2A8h] [rbp-18h]
setvbuf(stdout, 0LL, 2, 0LL);
size = 0x1000000LL;
s = malloc(0x1000000uLL);
memset(s, 0, 0x1000000uLL);
buf = s;
v23 = 0LL;
for ( i = 0; size; printf("Read %d\n", i) )
{
i = read(0, buf, size);
if ( (int)i <= 0 )
break;
size -= (int)i;
buf = (char *)buf + (int)i;
}
puts("FINISHED READING.");
Corefile::Corefile((Corefile *)v16, (unsigned __int8 *)s, (_BYTE *)buf - (_BYTE *)s);
Corefile::Process((Corefile *)v16);
Corefile::GetRegisters((Corefile *)v16);
std::vector<std::pair<unsigned long,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>>::vector(v15);
for ( j = 0LL; ; ++j )
{
NumberOfThreads = Corefile::GetNumberOfThreads((Corefile *)v16);
if ( j >= NumberOfThreads )
break;
Backtrace = (Backtrace *)Corefile::GetBacktrace((Corefile *)v16, j);
MappedRegisterSet = Corefile::GetMappedRegisterSet((Corefile *)v16, j);
FrameCount = (unsigned int)Backtrace::GetFrameCount(Backtrace);
for ( k = 0LL; k < FrameCount; ++k )
{
v3 = *((_QWORD *)Backtrace + 3 * k + 4);
v12[0] = *((_QWORD *)Backtrace + 3 * k + 3);
v12[1] = v3;
v12[2] = *((_QWORD *)Backtrace + 3 * k + 5);
SP = CallFrame::GetSP((CallFrame *)v12);
Binary = (Binary *)CallFrame::GetBinary((CallFrame *)v12);
Symbolizer::Symbolizer((Symbolizer *)v11, Binary, SP);
Symbolizer::Symbolicate[abi:cxx11](v10, v11);
MappedAddress = CallFrame::GetMappedAddress((CallFrame *)v12);
std::make_pair<unsigned long,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> &>(
v17,
&MappedAddress,
v10);
std::vector<std::pair<unsigned long,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>>::push_back(
v15,
v17);
std::pair<unsigned long,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>::~pair(v17);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v10);
}
}
Reporter::Reporter((Reporter *)v14, (Corefile *)v16);
Reporter::GenerateReport(v13, v14, v15);
v7 = std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(v13);
v8 = (const void *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::data(v13);
write(1, v8, v7);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v13);
std::vector<std::pair<unsigned long,std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>>>::~vector(v15);
Corefile::~Corefile((Corefile *)v16);
return 0;
}
What does the program do:
- Reading data from stdin with size 0x1000000
- Analyzing data like core file
- Print report
After sending simple string 'A'*0x1000000 program get crashed, and i try to fuzz this binary with afl and found a lot of bugs like a call malloc with specific size, but there is nothing here that could be exploited.
After loading binary to gdb and send valid core file, program has executed popen():
In Symbolizer::Symbolicate[abi:cxx11](v10, v11) called popen:
v3 = a2[1];
FileName = (const char *)Binary::GetFileName((Binary *)a2[2]);
v14 = snprintf(0LL, 0LL, "%s --obj=%s %p", *a2, FileName, v3);
s = (char *)malloc(v14 + 1);
v5 = a2[1];
v6 = (const char *)Binary::GetFileName((Binary *)a2[2]);
snprintf(s, v14 + 1, "%s --obj=%s %p", *a2, v6, v5);
stream = popen(s, "r");
It's looks like a command injection.
Open core file in hex editor we can find string which added to string and executed in popen:
After checking each string, the final exploit turns out like this: