Skip to content

Instantly share code, notes, and snippets.

@pwnhacker0x18
Last active July 18, 2022 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pwnhacker0x18/285bd66a206db6ca5d1aedf138a1502e to your computer and use it in GitHub Desktop.
Save pwnhacker0x18/285bd66a206db6ca5d1aedf138a1502e to your computer and use it in GitHub Desktop.
Google CTF 2022 (pwn) - madcore

MADCORE

Description: My coredump helper is crashing while handling a crash : (

Attachment

Reversing

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:

  1. Reading data from stdin with size 0x1000000
  2. Analyzing data like core file
  3. 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():

image

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.

Exploiting

Open core file in hex editor we can find string which added to string and executed in popen: image

After checking each string, the final exploit turns out like this: image

It takes several attempts to read flag: image

exploit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment