mcfx's blog - 2019年12月
/2019/12/
个人博客,(曾经)基本只放题解,现在随便写点啥了吧(CTFZone 2019 Quals Writeup
/archives/276/
2019-12-16T15:55:08+08:00# PPC
### Fridge
In the $$n\times n$$ matrix, each $$(i,j)$$ operation will add a matrix to the original one, and modulo each entry with some $$P$$. (For the first several levels, $$P=2$$, and $$P=8$$ or $$16$$ later)
We can compute a basis to solve this problem.
```python
import socket
import random
import sys
from copy import deepcopy
_debug=False
class Remote:
def __init__(self,ip,port):
self.s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect((ip,port))
self.buf=''
def send(self,s):
self.s.send(s.encode())
def recvbyte(self):
if len(self.buf)==0:
self.buf=self.s.recv(1024).decode().replace('\r','')
res=self.buf[0]
self.buf=self.buf[1:]
if _debug:
sys.stdout.write(res)
sys.stdout.flush()
return res
def unrecv(self,s):
self.buf=s+self.buf
def recvuntil(self,s):
res=''
while res[-len(s):]!=s:
res+=self.recvbyte()
return res
r=Remote('ppc-fridge.ctfz.one',31337)
def getlvl():
s=[]
s+=[list(map(lambda x:int(x,16),r.recvuntil('\n').split(' ')))]
for i in range(len(s[0])-1):
s+=[list(map(lambda x:int(x,16),r.recvuntil('\n').split(' ')))]
return s
def test(x,y):
r.send(str(x)+','+str(y)+'\n')
t=r.recvbyte()
if t=='t':
r.recvuntil('\n')
return True
r.unrecv(t)
return False
def hash(x):
res=0
for i in x:
for j in i:
res=res*2+j
return res
def umax(s):
res=0
for i in s:
res=max(res,max(i))
return res
def test8(cur,n,m):
print('test8=============================')
P=umax(cur)+1
def add(x,y):
res=deepcopy(x)
for i in range(n):
for j in range(m):
res[i][j]=(res[i][j]+y[i][j])%P
return res
def sub(x,y):
res=deepcopy(x)
for i in range(n):
for j in range(m):
res[i][j]=(res[i][j]+P-y[i][j])%P
return res
op=[[0 for i in range(m)]for j in range(n)]
for i in range(n):
for j in range(m):
if test(i,j):return
nxt=getlvl()
op[i][j]=sub(nxt,cur)
print(i,j,op[i][j])
cur=nxt
for i in range(10):
x=random.randint(0,n-1)
y=random.randint(0,m-1)
print('random test:',x,y)
if test(x,y):return
nxt=getlvl()
assert nxt==add(op[x][y],cur)
cur=nxt
sc=[[0 for i in range(m)]for j in range(n)]
sv=[[0 for i in range(m)]for j in range(n)]
for i in range(n):
for j in range(m):
oc=op[i][j]
ov=[[0 for i in range(m)]for j in range(n)]
ov[i][j]=1
flag=False
for x in range(n):
if flag:continue
for y in range(m):
if oc[x][y]:
if sc[x][y]==0:
print(x,y,oc)
sc[x][y]=oc
sv[x][y]=ov
flag=True
break
tc=sc[x][y]
tv=sv[x][y]
assert tc[x][y]
while oc[x][y]:
o=tc[x][y]//oc[x][y]
for uu in range(o):
tc=sub(tc,oc)
tv=sub(tv,ov)
oc,tc=tc,oc
ov,tv=tv,ov
sc[x][y]=tc
sv[x][y]=tv
oc=cur
ov=[[0 for i in range(m)]for j in range(n)]
print('try to find sol')
for x in range(n):
for y in range(m):
if oc[x][y]:
tc=sc[x][y]
tv=sv[x][y]
while oc[x][y]:
oc=add(oc,tc)
ov=add(ov,tv)
for x in range(n):
for y in range(m):
assert oc[x][y]==0
print('find sol:',ov)
for i in range(n):
for j in range(m):
for k in range(ov[i][j]):
print('work:',i,j)
if test(i,j):return
cur=getlvl()
def work():
global _debug
print('try to get lvl')
_debug=True
s=getlvl()
_debug=False
n=len(s)
m=len(s[0])
print(s)
test8(s,n,m)
while True:
work()
```
### Labyrinth
A maze. However, there are some hidden mines in the map. So just mark them and avoid them.
```python
import socket
import random
import sys
from copy import deepcopy
import json
import os
from pwn import *
_debug=True
r=remote('ppc-labyrinth.ctfz.one',4340)
N=41
M=201
def recvmap():
res=[]
for i in range(min(N,curx+601)):
res.append(r.recvuntil('\n').decode().strip())
if res[-1][:9]=='Exception':
print(res[-1])
markmine()
r.interactive()
return res
known_map={}
curx=0
def rmap():
global cury
fe=False
t=recvmap()
n=len(t)
for i in range(n):
if len(t[i])!=201:
if t[i][0]!='#':print(t)
assert t[i][0]=='#' and t[i][-1]=='#'
while len(t[i])一次(可能算是)失败的 BGP 尝试
/archives/275/
2019-12-06T19:39:00+08:00### 背景
教育网的 ipv6 大多是免流的。那么问题是如何找一个合适的梯子实现高速免流。教育网 ipv6 的出国线路大概有 HE、Cogentco、HKIX(有多个 ISP 都会经过 HKIX,就不详细列出了)。
HE 是大多数 ip 都会走线路,于是他 QoS 也比较严重。Cogentco 和 HKIX 则 QoS 的比较少。走 HKIX 的 VPS 还是有不少(自行搜索),不过价格一般还是不便宜。
而 Cogentco 线路有一些大服务商有,比如 vultr 的达拉斯回程和亚特兰大的去程,但是这两个的相反方向却都只是普通的HE 线路。要综合这两个线路得到一个双向 Cogentco 线路的梯子,其实可以通过一些操作,使得本地给 A 发包,如何 B 返回结果。但是感觉设置比较麻烦,就咕了。
这时我想到我恰好有一个(算是)闲置的 ASN 和一些 ipv6 资源,能不能用 BGP 实现这个双向 Cogentco 呢?
### 前提条件
一个 ASN,一些 ip 段。这些许多商家有售(比如 hostus)。比较便宜的可以去各大论坛或者群里问(比如 [https://t.me/MoeQing](https://t.me/MoeQing))
首先在 vultr 开两台机,装好必要的软件。
接下来在两台机器上都配置广播 ip,可以参考 [https://blog.ni-co.moe/public/560.html](https://blog.ni-co.moe/public/560.html)。
### 配置去程
由于我们想让这个 ip 段强制走其中一台进入,需要把他们之间连起来,并且再设置一下路由优先级。
把他们之间连起来可以参考 [https://lantian.pub/article/modify-website/join-dn42-experimental-network.lantian/](https://lantian.pub/article/modify-website/join-dn42-experimental-network.lantian/)。这里需要注意,为了让 zerotier 能正常分配公网 ipv6,需要运行 `zerotier-cli set 你的网络id allowGlobal=1`。
接下来是设置路由优先级。这里的需求很简单,只是为了让路由全都走某一台,那么可以让另一台的 AS Path 足够长,这样就不会被优先选择了。
具体来说,在 `/etc/bird/bird6.conf` 中,`protocol bgp vultr` 一段里,把 `export all;` 改成:
```
export filter {
bgp_path.prepend(你的 AS 号);
bgp_path.prepend(你的 AS 号);
...
bgp_path.prepend(你的 AS 号);
bgp_path.prepend(你的 AS 号);
};
```
这里要加多少个就自己决定了,只要让别人走不过来就行。
配好之后,重启 bird6,等一会路由更新,然后 trace 一下,发现去程确实走了 Cogentco。
### 配置回程
回程按理来说是不需要配置的,但是在达拉斯的机器上运行
```
mtr 2402:f000:2:f001::240:1
```
是走 GTT 到 Cogentco;而运行
```
mtr -a 你的ip 2402:f000:2:f001::240:1
```
却是走 NTT 到 HE。
为了配置这一部分,需要想办法调整回程线路,也就是 VPS 上的出口线路。
而根据 Vultr 给出的一些参考([https://www.vultr.com/docs/as20473-bgp-customer-guide](https://www.vultr.com/docs/as20473-bgp-customer-guide)),可以用 BGP Community 来控制宣告。
比如可以在 `export filter` 中加入
```
bgp_community.add((64609, 3257));
bgp_community.add((64699, 3257));
bgp_community.add((20473, 6000));
```
来只对外宣告到 AS3257(GTT)。
然而,这样仍然不能使上面的 mtr 都走 Cogentco。
### 问题分析
我找 Vultr 客服把我的 BGP 模式改成了全表。在所有出口路径中,我搜索了 45576(贵清的 ASN),发现只有
```
64515 65534 20473 6939 23911 23910 24348 45576
```
一条。也就是直接走 HE 的。
那么 GTT 和 Cogentco 是怎么走出来的就非常奇怪了。
这里我也分析不下去了,如果有人知道原因欢迎联系我。
后来我换了几个不同的贵清 ip 测试,发现有的是两种 mtr 都走 NTT-HE,有的是两种都走 GTT-Cogentco。
### 总结
BGP 实在是玄妙啊。。。