参加xman夏令营,大佬给我们带来了密码学课程。其中随机数部分感受颇深,记录下几个脚本。
1. 以时间作为种子的随机数
https://www.jarvisoj.com/ 的[xman2019]babyrpd
服务端代码
1 class Unbuffered(object): 2 def __init__(self, stream): 3 self.stream = stream 4 def write(self, data): 5 self.stream.write(data) 6 self.stream.flush() 7 def __getattr__(self, attr): 8 return getattr(self.stream, attr) 9 import sys 10 sys.stdout = Unbuffered(sys.stdout) 11 import signal 12 signal.alarm(600) 13 14 import random 15 import time 16 flag=open("/root/level0/flag","r").read() 17 18 random.seed(int(time.time())) 19 def check(): 20 recv=int(raw_input()) 21 if recv==random.randint(0,2**64): 22 print flag 23 return True 24 else: 25 print "atum tql" 26 return False 27 28 while 1: 29 if check(): 30 break
解决方法:
预测时间种子,进行攻击
1 #coding=utf-8 2 import socket 3 import random 4 import time 5 6 while True: 7 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 host = '47.97.215.88' 9 port = 20000 10 random.seed(int(time.time()+2)) #加上延迟所以+2秒 11 s.connect((host, port)) 12 s.send(str(random.randint(0,2**64))+' ') 13 print s.recv(1024)
2. java的Random随机数
https://www.jarvisoj.com/ 的[xman2019]mediumrpd
服务端代码:
1 class Unbuffered(object): 2 def __init__(self, stream): 3 self.stream = stream 4 def write(self, data): 5 self.stream.write(data) 6 self.stream.flush() 7 def __getattr__(self, attr): 8 return getattr(self.stream, attr) 9 import sys 10 sys.stdout = Unbuffered(sys.stdout) 11 import signal 12 signal.alarm(600) 13 import os 14 os.chdir("/root/level1") 15 16 flag=open("flag","r").read() 17 18 import subprocess 19 o = subprocess.check_output(["java", "Main"]) 20 tmp=[] 21 for i in o.split(" ")[0:3]: 22 tmp.append(int(i.strip())) 23 24 25 v1=tmp[0] % 0xffffffff 26 v2=tmp[1] % 0xffffffff 27 v3=tmp[2] % 0xffffffff 28 print v1 29 print v2 30 v3_get=int(raw_input()) 31 if v3_get==v3: 32 print flag
1 import java.util.Random; 2 public class Main { 3 public static void main(String[] args) { 4 Random random = new Random(); 5 System.out.println(random.nextInt()); 6 System.out.println(random.nextInt()); 7 System.out.println(random.nextInt()); 8 } 9 }
攻击方法
从题目获取到两个随机数v1,v2,通过已知公式,可以计算出v3
1 import socket 2 import random 3 import time 4 def liner (seed): 5 return ((seed*25214903917+11)&0xffffffffffff) 6 7 while True: 8 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 host = '47.97.215.88' 10 port = 20001 11 s.connect((host, port)) 12 v1=int(s.recv(1024)) 13 v2=int(s.recv(1024)) 14 for i in range(65536): 15 seed=v1*65536+i 16 if liner(seed)>>16==v2: 17 print seed 18 v3=liner(liner(seed))>>16 19 s.send(str(v3)+' ') 20 print s.recv(1024)
3. python的random
来源是:Mersenne Twister
大佬说php的mt_rand(可以用php_mt_seed攻击),ruby的rand(),python的random都可以攻击,但我只弄出python的版本
题目为https://www.jarvisoj.com/ 的[xman2019]hardrpd
参考文章:https://ddaa.tw/30c3ctf_2013_number_100_guess.html
服务端代码:
1 class Unbuffered(object): 2 def __init__(self, stream): 3 self.stream = stream 4 def write(self, data): 5 self.stream.write(data) 6 self.stream.flush() 7 def __getattr__(self, attr): 8 return getattr(self.stream, attr) 9 import sys 10 sys.stdout = Unbuffered(sys.stdout) 11 import os 12 os.chdir("/root/level2") 13 14 from random import * 15 16 17 while 1: 18 a=raw_input("#") 19 target=getrandbits(32) 20 if a!=str(target): 21 print target 22 else: 23 print open("flag","rb").read()
攻击脚本:(改写至TokyoWestern CTF WriteUp by r3kapig )
1 #coding=utf-8 2 import socket 3 import random 4 import time 5 6 7 def unBitshiftRightXor (value,shift): 8 i = 0 9 result = 0 10 while i * shift < 32: 11 partMask = right((-1 << (32 - shift)) , (shift * i)) 12 part = value & partMask 13 value ^= right(part , shift) 14 result |= part 15 i+=1 16 return result 17 def unBitshiftLeftXor(value, shift, mask): 18 i = 0; 19 result = 0; 20 while i * shift < 32: 21 partMask = right(-1 , (32 - shift)) << (shift * i) 22 part = value & partMask 23 value ^= (part << shift) & mask 24 result |= part 25 i += 1 26 return result 27 28 def rev(nums): 29 state=[] 30 for i in nums: 31 value = i; 32 value = unBitshiftRightXor(value, 18) 33 value = unBitshiftLeftXor(value, 15, 0xefc60000) 34 value = unBitshiftLeftXor(value, 7, 0x9d2c5680) 35 state.append(unBitshiftRightXor(value, 11)) 36 return state 37 38 def sign(iv): 39 if(iv&0x80000000): 40 iv = -0x100000000 + iv 41 return iv 42 43 def nextState(state): 44 for i in range(624): 45 y = (state[i] & 0x80000000) + (state[(i + 1) % 624] & 0x7fffffff) 46 next = right(y,1); 47 next ^= state[(i + 397) % 624] 48 if ((y & 1L) == 1L): 49 next ^= 0x9908b0df 50 state[i] = next 51 52 def nextNumber(state): 53 currentIndex=0 54 tmp = state[currentIndex]; 55 tmp ^= right(tmp , 11) 56 tmp ^= (tmp << 7) & 0x9d2c5680 57 tmp ^= (tmp << 15) & 0xefc60000 58 tmp ^= right(tmp , 18) 59 return tmp 60 61 def right(n,bit): #python没有>>>运算符,这个函数用作代替 62 x=n 63 if n<0 and bit>0: 64 n=(2147483648*2+n)>>bit 65 else: 66 n=n>>bit 67 return n 68 69 def crack_prng(outputs_624_list): 70 state=rev(outputs_624_list) 71 stateList = state[:] 72 nextState(state) 73 r = random.Random() 74 state = (3, tuple(stateList + [624]), None) 75 r.setstate(state) 76 return r 77 ''' 78 #本地测试代码 79 n=[random.getrandbits(32) for i in range(625)] 80 r=crack_prng(n[:-1]) 81 print n[-1],r.getrandbits(32) 82 ''' 83 n=[] 84 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 85 host = '47.97.215.88' 86 port = 20002 87 s.connect((host, port)) 88 for i in range(624): 89 print s.recv(1024),i, 90 s.send(' ') 91 n.append(int(s.recv(1024))) 92 r=crack_prng(n) 93 s.send(str(r.getrandbits(32))+' ') 94 print s.recv(1024),s.recv(1024)