mysql hypot_几道web题简单总结

本文总结了两道Python web安全题目,涉及Python的eval函数利用和MySQL弱口令攻击。第一题中,通过eval函数的代码注入实现任务目标;第二题则展示了如何利用HTTP请求修改进程行为,读取服务器文件,最终获取敏感信息。
摘要由CSDN通过智能技术生成

拖了好长时间,总结一下这一段时间做的几道值得记录一下的题目,有的没做出来,但是学习到了新的东西

1.homebrew event loop

ddctf的一道题目,学到了python eval函数的用法,首先分析题目:

#-*- encoding: utf-8 -*-#written in python 2.7

__author__ = 'garzon'

from flask importFlask, session, request, Responseimporturllib

app= Flask(__name__)

app.secret_key= '*********************' #censored

url_prefix = '/d5af31f99147e857'

defFLAG():return 'FLAG_is_here_but_i_wont_show_you' #censored

deftrigger_event(event):

session['log'].append(event)if len(session['log']) > 5: session['log'] = session['log'][-5:]if type(event) ==type([]):

request.event_queue+=eventelse:

request.event_queue.append(event)def get_mid_str(haystack, prefix, postfix=None):

haystack= haystack[haystack.find(prefix) +len(prefix):]if postfix is notNone:

haystack=haystack[:haystack.find(postfix)]returnhaystackclass RollBackException: pass

defexecute_event_loop():

valid_event_chars= set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789:;#')

resp=Nonewhile len(request.event_queue) >0:

event= request.event_queue[0] #`event` is something like "action:ACTION;ARGS0#ARGS1#ARGS2......"

request.event_queue = request.event_queue[1:]if not event.startswith(('action:', 'func:')): continue

for c inevent:if c not in valid_event_chars: break

else:

is_action= event[0] == 'a'action= get_mid_str(event, ':', ';') #index

args = get_mid_str(event, action + ';').split('#') #True#True

try:

event_handler= eval(action + ('_handler' if is_action else '_function'))

ret_val=event_handler(args)exceptRollBackException:if resp is None: resp = ''resp+= 'ERROR! All transactions have been cancelled.
'resp+= 'Go back to index.html
'session['num_items'] = request.prev_session['num_items']

session['points'] = request.prev_session['points']break

exceptException, e:if resp is None: resp = ''

#resp += str(e) # only for debugging

continue

if ret_val is notNone:if resp isNone:

resp=ret_valelse:

resp+=ret_valif resp is None or resp == '': resp = ('404 NOT FOUND', 404)

session.modified=Truereturnresp

@app.route(url_prefix+ '/')defentry_point():

querystring=urllib.unquote(request.query_string)

request.event_queue=[]if querystring == '' or (not querystring.startswith('action:')) or len(querystring) > 100:

querystring= 'action:index;False#False'

if 'num_items' not insession:

session['num_items'] =0

session['points'] = 3session['log'] =[]

request.prev_session=dict(session)

trigger_event(querystring)returnexecute_event_loop()#handlers/functions below --------------------------------------

defview_handler(args):

page=args[0]

html= ''html+= '[INFO] you have {} diamonds, {} points now.
'.format(session['num_items'], session['points'])if page == 'index':

html+= 'View source code
'html+= 'Go to e-shop
'html+= 'Reset
'

elif page == 'shop':

html+= 'Buy a diamond (1 point)
'

elif page == 'reset':del session['num_items']

html+= 'Session reset.
'html+= 'Go back to index.html
'

returnhtmldefindex_handler(args):

bool_show_source=str(args[0])

bool_download_source= str(args[1])if bool_show_source == 'True':

source= open('eventLoop.py', 'r')

html= ''

if bool_download_source != 'True':

html+= 'Download this .py file
'html+= 'Go back to index.html
'

for line insource:if bool_download_source != 'True':

html+= line.replace('&', '&').replace('\t', ' ' * 4).replace(' ', ' ').replace('', '>').replace('\n', '
')else:

html+=line

source.close()if bool_download_source == 'True':

headers={}

headers['Content-Type'] = 'text/plain'headers['Content-Disposition'] = 'attachment; filename=serve.py'

return Response(html, headers=headers)else:returnhtmlelse:

trigger_event('action:view;index')defbuy_handler(args):

num_items=int(args[0])if num_items <= 0: return 'invalid number({}) of diamonds to buy
'.format(args[0])

session['num_items'] +=num_items

trigger_event(['func:consume_point;{}'.format(num_items), 'action:view;index'])defconsume_point_function(args):

point_to_consume=int(args[0])if session['points'] < point_to_consume: raiseRollBackException()

session['points'] -=point_to_consumedefshow_flag_function(args):

flag=args[0]#return flag # GOTCHA! We noticed that here is a backdoor planted by a hacker which will print the flag, so we disabled it.

return 'You naughty boy! ;)
'

defget_flag_handler(args):if session['num_items'] >= 5:

trigger_event('func:show_flag;' + FLAG()) #show_flag_function has been disabled, no worries

trigger_event('action:view;index')if __name__ == '__main__':

app.run(debug=False, host='0.0.0.0')

这道题目首先通读源码是必须的,另一个必须要了解到的出题点在eval()函数这个地方,eval中可以传入#来注释掉后面的部分

45e21bdf92ef722ff43aedc15bc86a54.png

从上图可以看出来,此时eval会忽略掉#后面的所有字符串,以及要做出这道题的另一个点:

打破程序进行的流程,先加钻石数量再检验钱数,并且可以给事件传入一个列表,那么先加钻石,在检验钱之前去getflag即可,而且这里会把flag带到log中去,总之就是在一个正常的处理序列中去插入一个新的事件,因为eval这里可控,所以刚开始就应该反映到出题点,实际上就是代码注入

在这里!

2.mysql弱口令

#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 12/1/2019 2:58 PM#@Author : fz#@Site :#@File : agent.py#@Software: PyCharm

importjsonfrom BaseHTTPServer importHTTPServer, BaseHTTPRequestHandlerfrom optparse importOptionParserfrom subprocess importPopen, PIPEclassRequestHandler(BaseHTTPRequestHandler):defdo_GET(self):

request_path=self.pathprint("\n----- Request Start ----->\n")print("request_path :", request_path)print("self.headers :", self.headers)print("

self.send_response(200)

self.send_header("Set-Cookie", "foo=bar")

self.end_headers()

result=self._func()

self.wfile.write(json.dumps(result))defdo_POST(self):

request_path=self.path#print("\n----- Request Start ----->\n")

print("request_path : %s", request_path)

request_headers=self.headers

content_length= request_headers.getheaders('content-length')

length= int(content_length[0]) if content_length else0#print("length :", length)

print("request_headers : %s" %request_headers)print("content : %s" %self.rfile.read(length))#print("

self.send_response(200)

self.send_header("Set-Cookie", "foo=bar")

self.end_headers()

result=self._func()

self.wfile.write(json.dumps(result))def_func(self):

netstat= Popen(['netstat', '-tlnp'], stdout=PIPE)

netstat.wait()

ps_list=netstat.stdout.readlines()

result=[]for item in ps_list[2:]:

tmp=item.split()

Local_Address= tmp[3]

Process_name= tmp[6]

tmp_dic= {'local_address': Local_Address, 'Process_name': Process_name}

result.append(tmp_dic)returnresult

do_PUT=do_POST

do_DELETE=do_GETdefmain():

port= 8123

print('Listening on localhost:%s' %port)

server= HTTPServer(('0.0.0.0', port), RequestHandler)

server.serve_forever()if __name__ == "__main__":

parser=OptionParser()

parser.usage=("Creates an http-server that will echo out any GET or POST parameters, and respond with dummy data\n"

"Run:\n\n")

(options, args)=parser.parse_args()

main()

这道题主要是来攻击mysql连接的客户端,这个题目给了agent.py 是用来检测是不是服务器上存在mysqld进程,而判断是通过do_get和do_post两个函数确定的,这两个函数都会调用_func函数,返回进程名,然后do_get 和do_post再把_func的返回值输出,

所以只需要让最后输出的存在mysqld就行了,然后就可以在服务器上读取客户端的文件。

3b73fce1726dd2434a578365588543e4.png

6010ce397ec0ed2f9e0095416171f4ac.png

这里读取客户端的.mysql_histoty文件,这个文件存储了用户登陆mysql服务器所执行的命令,也可以读取.bash_history

30c3903a820a18428289fde797dffc83.png

在这里又可以读到web的源码地址,所以可以继续读取它:

a667375d6c5833f0bb84bca57124972b.png

在这里能够发现flag所在的库和表,所以就可以读取表中的内容,又因为linux下,mysql安装后,数据库的数据默认存放在/var/lib/mysql目录下,所以可以直接访问其中的库表,所以可以直接读取

/var/lib/mysql/security/flag.ibd

3.just soso

这道题比较常规

<?phperror_reporting (0);$file = $_GET["file"];$payload = $_GET["payload"];if(!isset($file)){echo 'Missing parameter'.'
';

}if(preg_match("/flag/",$file)){die('hack attacked!!!');

}

@include($file);if(isset($payload)){$url = parse_url($_SERVER['REQUEST_URI']);parse_str($url['query'],$query);foreach($query as $value){if (preg_match("/flag/",$value)) {die('stop hacking!');exit();

}

}$payload = unserialize($payload);

}else{echo "Missing parameters";

}?>

这里主要记录一下绕过parse_url,这里会检测flag字符串,但是要是让parse_url

3f99996c82ecd89f724e260f995531f4.png

e138874e823451a7464e800dbe7589a2.png

这样就能使parse_url返回false,这样绕过对flag的过滤,然后后面就是常规的反序列化漏洞,这里要记住最后的序列化的数据因为有不可见字符所以需要urlencode一下

4.math

if(!isset($_GET['c'])){show_source(__FILE__);

}else{//例子 c=20-1

$content = $_GET['c'];if (strlen($content) >= 80) {die("太长了不会算");

}$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];foreach ($blacklist as $blackitem) {if (preg_match('/' . $blackitem . '/m', $content)) {die("请不要输入奇奇怪怪的字符");

}

}//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp

$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);foreach ($used_funcs[0] as $func) {if (!in_array($func, $whitelist)) {die("请不要输入奇奇怪怪的函数");

}

}//帮你算出答案

eval('echo '.$content.';');

}

方法一:

这道题主要还是构造没有字母的shell,这里面又提供了进制转换的函数base_convert(),说明可以用0-9a-z 36个字符,那么就可以构造shell,这里主要通过分析一个payload:

$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat flag.php

这里通过构造动态函数,首先base_convert()构造hex2bin,把16进制转换为字符串,再通过“_GET” -> 16进制表示,再到10进制表示,然后反过来dechex()->hex2bin(),然后结合动态函数

比如$a="_GET";$$a{c}(($$a){d}); 这样将实际的payload放在GET参数中,从而来减小长度。

另外一个点是php的数组不仅可以通过[]来进行索引,还可以通过{}来进行索引。

方法2:

另一种构造出_GET的方法是通过异或字符串:

比如要得到_G,则可以通过:

3e12ab81698b8bb8c0d8a686c8c0a60a.png

具体怎么得出:可以通过“_G”和两个字符异或:

for($j=0;$j<10;$j = $j+1){for($i=0;$i<10;$i = $i+1){echo $i.$j." ";echo "_G"^($j).($i);echo "\n";

}}

888d417eb560c91a5163a2a4c04118f1.png

可以得到两位字符串,这里也可以选3位或者4位跑,但是因为得到的字符串需要在白名单里面找,所以太长了找不到,所以选两位最好,一位会增加payload长度,因此is是在白名单里存在的,所以就可以使用,同样的方法去找“ET”,最后

还是去构造动态函数就可以了。

$abs=(is_finite^(6).(4)).(rad2deg^(7).(5));$$abs{acos}($$abs{ceil})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值