Category - MatesCTF2018

在cap.shao同学的说明下完成的,只能说比赛中的Pwn题还是需要多练习。这道题其实挺基础的,没有奇技淫巧,只是需要几个点联系起来。

一个很普通的列表题目,四个选项,实际上只用到了三个:

  1. buy_friut,实际上是往一个全局的basket链表中插入item,有apple和banana两种水果,对应不同的描述的buffer长度。
  2. create_invoice,打印basket链表中的item,有一个格式化字符串漏洞。
  3. change_label,改变一个长度10的字符串的值,但修改需要一个bool值为true,这个bool值在整个binary中都没有暴露出来。

水果的item是一个单链表结构,但实际上不会利用到next指针,结构如下:

  1. struct fruit_item {
  2. struct fruit_item *next;
  3. int index;
  4. short int quantity;
  5. short int total;
  6. bool can_change_label;
  7. char label[10];
  8. bool type;
  9. char buffer[128];
  10. };

type为false/0时是apple,true/!0是banana。两者的不同在于,buffer会被分为两部分,记做baseextra,正常来说,base是不可控的,extra是可控(在buy_fruit时可以自行指定)的。最后一列的information,'.'之前的是base,之后的是extra
enter image description here

打发票时,base部分是直接用printf打印的,因此可能存在格式化字符串漏洞,要想办法控制base部分。读反编译代码可知,extra就是buffer的首地址,但base的首地址不同:作为apple时,basebuffer+64开始,作为banana时,basebuffer+96开始。如果能够将一个banana改成apple,那么就有可能将原来banana的extra部分当成apple的base打印出来,这一部分的长度最多有96-64=32字节。

type可以通过溢出label来修改:change_label是利用sc

题目是用flask搭建了一个web应用,目的是通过伪造token来登入admin页面:
enter image description here

通过所给的login接口可以得到user权限的token,因此得想办法通过user的token来伪造admin的token。token使用HMAC和AES双重加密,一个token的格式如下:
enter image description here

hmac是用于验证enc_token的,里面包括name、role和hmac的key。将key放在enc_token后面应该是一种应用模式而不是有漏洞的设计,主要的问题在于使用了AES的ECB模式。ECB下,每个block都是相互独立的,因此即便不知道AES的秘钥也有办法构造出密文。

  1. from base64 import b64encode, b64decode
  2. import requests
  3. from Crypto.Hash import HMAC
  4. host = 'http://ec2-13-229-142-46.ap-southeast-1.compute.amazonaws.com:9999'
  5. # host = 'http://localhost:9999'
  6. def get_token(name):
  7. assert 0 < len(name) <= 1024
  8. ses = requests.Session()
  9. data = { 'name': name }
  10. ses.post(host+'/login', data=data)
  11. token = ses.cookies['token']
  12. mac = token[-32:]
  13. token = token[:-32]
  14. return b64decode(token), mac
  15. def try_login(token):
  16. ses = requests.Session()
  17. ses.cookies['token'] = token
  18. resp = ses.get(host)
  19. print resp.text
  20. payload = 'cir'+ 'q'*12 # 最后的':'由题目本身加上的
  21. enc, _ = get_token(payload)
  22. name = en