在cap.shao同学的说明下完成的,只能说比赛中的Pwn题还是需要多练习。这道题其实挺基础的,没有奇技淫巧,只是需要几个点联系起来。
一个很普通的列表题目,四个选项,实际上只用到了三个:
水果的item是一个单链表结构,但实际上不会利用到next指针,结构如下:
struct fruit_item {
struct fruit_item *next;
int index;
short int quantity;
short int total;
bool can_change_label;
char label[10];
bool type;
char buffer[128];
};
type
为false/0时是apple,true/!0是banana。两者的不同在于,buffer
会被分为两部分,记做base
和extra
,正常来说,base是不可控的,extra是可控(在buy_fruit时可以自行指定)的。最后一列的information,'.'
之前的是base
,之后的是extra
。
打发票时,base
部分是直接用printf
打印的,因此可能存在格式化字符串漏洞,要想办法控制base
部分。读反编译代码可知,extra
就是buffer
的首地址,但base
的首地址不同:作为apple时,base
从buffer+64
开始,作为banana时,base
从buffer+96
开始。如果能够将一个banana改成apple,那么就有可能将原来banana的extra
部分当成apple的base
打印出来,这一部分的长度最多有96-64=32字节。
type
可以通过溢出label
来修改:change_label是利用sc
题目是用flask搭建了一个web应用,目的是通过伪造token来登入admin页面:
通过所给的login接口可以得到user权限的token,因此得想办法通过user的token来伪造admin的token。token使用HMAC和AES双重加密,一个token的格式如下:
hmac是用于验证enc_token的,里面包括name、role和hmac的key。将key放在enc_token后面应该是一种应用模式而不是有漏洞的设计,主要的问题在于使用了AES的ECB模式。ECB下,每个block都是相互独立的,因此即便不知道AES的秘钥也有办法构造出密文。
from base64 import b64encode, b64decode
import requests
from Crypto.Hash import HMAC
host = 'http://ec2-13-229-142-46.ap-southeast-1.compute.amazonaws.com:9999'
# host = 'http://localhost:9999'
def get_token(name):
assert 0 < len(name) <= 1024
ses = requests.Session()
data = { 'name': name }
ses.post(host+'/login', data=data)
token = ses.cookies['token']
mac = token[-32:]
token = token[:-32]
return b64decode(token), mac
def try_login(token):
ses = requests.Session()
ses.cookies['token'] = token
resp = ses.get(host)
print resp.text
payload = 'cir'+ 'q'*12 # 最后的':'由题目本身加上的
enc, _ = get_token(payload)
name = en