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 实在是玄妙啊。。。