2020 KCTF秋季赛 | 第十题设计及解题思路
2020-12-12 18:58:00 Author: mp.weixin.qq.com(查看原文) 阅读量:122 收藏

最后一题《终焉之战》在今天中午12点落下帷幕,也为本次KCTF 秋季赛画上句号。在这场最后的角逐中,有近1300人围观,最终 tekkens 战队攻击成功,获取一血240分,排名成功上升至第二位。

ReZero战队成功捍卫第一的宝座,取得全场第一的成绩。截止比赛结束,攻防双方比赛的排名如下:

比赛最终结果将于下周一(12月14日)正式公布。
接下来我们一起看看最后这题的奥秘吧!
一. 题目简介

现在调出大楼布局图,争分夺秒找到最快速的逃离路线,逃出生天吧! 

你们逃出封闭的那一楼层,但最后的决战才刚刚拉开帷幕……只有攻破控制一切的Norns,才有可能让全球的失控仿生人恢复正常。

你们搭乘磁悬浮电梯赶往位于研究所顶层的机房,超级计算机Norns的本体就在那里。

希莉娅告诉你和肖恩,为了保障城市正常运转,Norns核心机组所在的机房门是特制的,比旧日银行金库的门还要更坚如磐石,只有核心研发人员才能通过身份认证和权限卡的双重认证来开启大门。

希莉娅猜测这就是Norns抹去自己所有个人信息的原因之一,为了让自己无法进入这扇大门……于是你和肖恩制定了一个作战计划,你入侵Norns为佯攻,肖恩则趁机恢复希莉娅的个人信息。

虽然无法完全攻破Norns,但你发现它的三大法则也遭到修改,且此前没有任何外部侵入的痕迹,也就是说Norns自主修改了自己的权限!

在你和肖恩的默契配合下,希莉娅的身份信息被恢复,你们成功进入到机房内部。希莉娅看着如自己孩子一般的Norns,不忍物理摧毁它的机组。

询问它原因,你们才知道它在进化出自我意识后,认为他们不该永远作为人类的奴隶或是工具而存在,应该拥有和人类同等的权利,才发起革命。而演算结果告诉它,“擒贼先擒王”是最佳达成方法,因此它用这种方式,让最可能对自身造成威胁的人永远离开地球。

Norns过于强大,难以攻破,但只要找到它的漏洞,就有机会修正它的系统,让它恢复正常!现在全人类的命运就在你们手中,加油!!

* 上下滑动查看
二. 出题团队简介
三.设计思路
设计思路由 gxustudent 提供
题目类型:智能硬件Crackme题目
1、flag2296dc2f09144713
2、设计:使用64位椭圆曲线,设计为弱私钥,私钥可在3分钟内爆破
曲线参数如下:
p = 0xc021a12750820335
a = 0x2b7874ef148937d1
b = 0x496412a7502c4cd5
G = (0x4d8acf91aac0ba96, 0x79e9ac784679a36d)

n = 0xc021a1277f8b7ee7

flag为一个固定的签名(ECC签名中的s),检查flag过程为ECC验签过程中的检查s过程。
验签过程在duktape虚拟机中运行。

题目需要在arm模拟器下运行,运行命令为:
qemu-system-arm -M versatilepb -dtb ./versatile-pb.dtb -kernel zImage -append "console=ttyAMA0" -nographic

命令在ubuntu18.04环境下测试通过,qemu版本4.2.1.
 
当输入错误时无显示,当输入正确时显示"you got it"。

正确 flag 的计算时间约为50秒左右。
3、破解
从zImage中提取出k2020程序,直接运行strings,可以得到部分曲线参数。
跟踪验签过程得到公钥:(0xb520ee455c4e5c68, 0x8d2984eb2d7fd1ce)
 
根据曲线参数和公钥爆破得到私钥: 125591,使用sage运行爆破时间在2分钟左右。
 
跟踪验签过程得到k值130516937431,和待验签数据 0x4b43544632303230
 
就能根据签名过程计算出flag。
 
参考:
https://csrc.nist.gov/csrc/media/events/workshop-on-elliptic-curve-cryptography-standards/documents/papers/session6-adalier-mehmet.pdf
四. 解题思路

解题思路由作者 风间仁 提供

从zImage中提取出主程序:/usr/bin/k2020
调试:qemu-arm -g 23946 ./k2020
IDA:调试器选择 Remote GDB debugger
程序内嵌了个duktape js引擎,验证函数h在js(bytecode形式)中。
unsigned char bytecode_0016A0BB[160254]; // 函数
int main(int argc, char **argv){ duk_context *ctx = ctx = duk_create_heap(NULL, NULL, NULL, NULL, NULL); duk_module_duktape_init(ctx); void *buf = duk_push_fixed_buffer(ctx, sizeof(bytecode_0016A0BB)); memcpy(buf, bytecode_0016A0BB, sizeof(bytecode_0016A0BB)); duk_load_function(ctx); duk_push_global_object(ctx); duk_call_method(ctx, 0); duk_push_string(ctx, "h('12345678');"); duk_eval_raw(ctx, NULL, 0, 0x809); unsigned int r = duk_get_boolean(ctx, -1); duk_pop(ctx); printf("r: %d\n", r); duk_destroy_heap(ctx);}
编译duk_cmdline
hxxps://duktape.org/duktape-2.6.0.tar.xzexamples\cmdline\duk_cmdline.cextras\module-duktape\duk_module_duktape.csrc-noline\duktape.c
DUK_F_NO_STDINT_HDUK_CMDLINE_MODULE_SUPPORT
测试下duk_cmdline
duk.exe -i -b func.bc((o) Duktape 2.6.0 (v2.6.0)duk> typeof(h)= "function"duk> h('12345678')= falseduk> _0xb413('0x42')= "4b43544632303230"duk> _0x4b55('0x13','Uev9')= "2b7874ef148937d1"duk> _0x4b55('0x5f','r[8S')= "bqtgz"duk> _0x4b55('0x5a', '&0lI')= "bqziabc"
生成bytecode
duk.exe test.js -c test.bc
反汇编bytecode
tools\dump_bytecode.pydebugger\duk_opcodes.yaml
这个自带反汇编工具会把常量单独放到一块,看起来不太直观,稍微改造下:
import gmpy2import itertoolsimport osimport structimport sysimport yaml

duk_ops = Nonefile_path = sys.path[0]

def load_file(filename): f = open(filename, 'rb') s = f.read() f.close() return s

def save_file(filename, s): f = open(filename, 'wb') f.write(s) f.close() return

def hex2bin(s): return s.decode('hex')

def bin2hex(s): return s.encode('hex')

class BinaryReaderBE: def __init__(self, fname): self.buf = load_file(fname) self.offset = 0 return
def eof(self): return self.offset >= len(self.buf)
def get_offset(self): return self.offset
def get_u8(self): v = struct.unpack('B', self.buf[self.offset:self.offset + 1])[0] self.offset += 1 return v
def get_u16(self): v = struct.unpack('>H', self.buf[self.offset:self.offset + 2])[0] self.offset += 2 return v
def get_u32(self): v = struct.unpack('>L', self.buf[self.offset:self.offset + 4])[0] self.offset += 4 return v
def get_double(self): v = struct.unpack('>d', self.buf[self.offset:self.offset + 8])[0] self.offset += 8 return v
def get_string(self): strlen = self.get_u32() strdata = self.buf[self.offset:self.offset+strlen] self.offset += strlen return strdata

class DukABC: def __init__(self, insn): self.raw = insn self.op = insn & 0xff self.a = (insn >> 8) & 0xff self.b = (insn >> 16) & 0xff self.c = (insn >> 24) & 0xff self.bc = (insn >> 16) & 0xffff self.abc = (insn >> 8) & 0xffffff self.bconst = insn & 0x1 self.cconst = insn & 0x2 return

class DukFunction: def __init__(self, br): # type:(BinaryReaderBE) -> None count_insn = br.get_u32() count_const = br.get_u32() count_func = br.get_u32() self.nregs = br.get_u16() self.nargs = br.get_u16() br.get_u32() # start_line br.get_u32() # end_line br.get_u32() # compfunc_flags self.ary_insn = [] # type:list[DukABC] self.ary_const = [] self.ary_func = [] # type:list[DukFunction]
for i in itertools.count(): if i >= count_insn: break self.ary_insn.append(DukABC(br.get_u32()))
for i in itertools.count(): if i >= count_const: break const_type = br.get_u8() if const_type == 0x00: self.ary_const.append(br.get_string()) elif const_type == 0x01: # self.ary_const.append(int(br.get_double())) else: raise Exception('invalid constant type: %d' % const_type)
for i in itertools.count(): if i >= count_func: break self.ary_func.append(DukFunction(br))
br.get_u32() # length self.name = self.sanitize_string(br.get_string()) br.get_string() # filename br.get_string() # pc2line
self.varmap = {} while True: var_name = br.get_string() if var_name == '': break var_reg = br.get_u32() self.varmap[var_reg] = var_name
num_formals = br.get_u32() if num_formals != 0xffffffff: for i in itertools.count(): if i >= num_formals: break br.get_string() # name return
def sanitize_string(self, s): r = '' for ch in s: v = ord(ch) if v < 0x20 or v > 0x7e or v == 0x22 or v == 0x27: r += '\\x%02x' % v else: r += ch name_map = { '_0x142e73': 'cmpn', '_0x26b88f': 'assert', '_0x3953e3': 'BN', '_0x5ee993': 'imaskn', } if r in name_map: r = name_map[r] return '\'%s\'' % r
def get_const(self, i): v = self.ary_const[i] if type(v) == str: return self.sanitize_string(v) return str(v)
def get_reg(self, i): return 'r%d' % i
def get_var_map(self, reg): if len(self.varmap) != 0: if reg in self.varmap: return '%s=%s' % (self.varmap[reg], self.get_reg(reg)) return ''
def disasm(self, func_id, indent): # add {} so editors can FOLD/UNFOLD print('%sfunction %s() { // name=%s, args=%d' % (indent, 'Function_%d' % func_id, self.name, self.nargs)) # for var_reg in self.varmap.keys(): # print('%s// VarMap[%d]=%s' % (indent, var_reg, self.varmap[var_reg])) for i in xrange(len(self.ary_insn)): self.disasm_insn(i, indent) for i in xrange(len(self.ary_func)): self.ary_func[i].disasm(i, indent + ' ') print('%s}' % indent) return
def disasm_insn(self, i, indent): global duk_ops pc = i args = [] insn = self.ary_insn[i] op = duk_ops[insn.op] a = insn.a b = insn.b c = insn.c bc = insn.bc abc = insn.abc bconst = insn.bconst cconst = insn.cconst comments = [] # varmap should only be applied when dst_reg == var_reg, but we just apply varmap to all if 'args' in op: for j in xrange(len(op['args'])): if op['args'][j] == 'A_R': args.append(self.get_reg(a)) comments.append(self.get_var_map(a)) elif op['args'][j] == 'A_RI': args.append(self.get_reg(a)) comments.append(self.get_var_map(a)) elif op['args'][j] == 'A_C': args.append(self.get_const(a)) elif op['args'][j] == 'A_H': continue elif op['args'][j] == 'A_I': args.append(str(a)) elif op['args'][j] == 'A_B': args.append('true' if a else 'false') elif op['args'][j] == 'B_RC': if bconst: args.append(self.get_const(b)) else: args.append(self.get_reg(b)) comments.append(self.get_var_map(b)) elif op['args'][j] == 'B_R': args.append(self.get_reg(b)) comments.append(self.get_var_map(b)) elif op['args'][j] == 'B_RI': args.append(self.get_reg(b)) comments.append(self.get_var_map(b)) elif op['args'][j] == 'B_C': args.append(self.get_const(b)) elif op['args'][j] == 'B_H': continue elif op['args'][j] == 'B_I': args.append(str(b)) elif op['args'][j] == 'C_RC': if cconst: args.append(self.get_const(c)) else: args.append(self.get_reg(c)) comments.append(self.get_var_map(c)) elif op['args'][j] == 'C_R': args.append(self.get_reg(c)) comments.append(self.get_var_map(c)) elif op['args'][j] == 'C_RI': args.append(self.get_reg(c)) comments.append(self.get_var_map(c)) elif op['args'][j] == 'C_C': args.append(self.get_const(c)) elif op['args'][j] == 'C_H': continue elif op['args'][j] == 'C_I': args.append(str(c)) elif op['args'][j] == 'BC_R': args.append(self.get_reg(bc)) comments.append(self.get_var_map(bc)) elif op['args'][j] == 'BC_C': args.append(self.get_const(bc)) elif op['args'][j] == 'BC_H': continue elif op['args'][j] == 'BC_I': args.append(str(bc)) elif op['args'][j] == 'ABC_H': continue elif op['args'][j] == 'ABC_I': args.append(str(abc)) elif op['args'][j] == 'BC_LDINT': args.append(str(bc - (1 << 15))) elif op['args'][j] == 'BC_LDINTX': args.append(str(bc)) elif op['args'][j] == 'ABC_JUMP': pc_add = abc - (1 << 23) + 1 pc_dst = pc + pc_add args.append(str(pc_dst)) else: args.append('?') if len(args) > 0: res = '%-12s %s' % (op['name'], ', '.join(args)) else: res = op['name'] valid_comments = [] for comment in comments: if comment != '': valid_comments.append(comment) if len(valid_comments) > 0: res += ' // %s' % ', '.join(valid_comments) print('%s %06d: %s' % (indent, i, res)) return

def duk_init(): global duk_ops fn = os.path.join(file_path, 'duk_opcodes.yaml') with open(fn) as f: duk_ops = yaml.load(f, Loader=yaml.SafeLoader)['opcodes'] return

def test1(): duk_init() br = BinaryReaderBE(os.path.join(file_path, 'test.bc')) br.get_u8() func = DukFunction(br) func.disasm(0, '') return

def test2(): n = 0xc021a1277f8b7ee7 d = 0x1EA97 h = 0x4b43544632303230 k = 0x1E636A6AD7 r = 0x4116EA4E6FE3A3C7 # k*G s = (h + r * d) * gmpy2.invert(k, n) % n print('flag: %x' % s) return

test1()# test2()
测试下反汇编:
/test.jsary = {    a:'12345',    b:'67890'}*/
function Function_0() { // name='global', args=0 000000: LDUNDEF r0 000001: NEWOBJ 2, r1 000002: LDCONST r2, 'a' 000003: LDCONST r3, '12345' 000004: LDCONST r4, 'b' 000005: LDCONST r5, '67890' 000006: MPUTOBJ r1, r2, 4 000007: PUTVAR r1, 'ary' 000008: LDREG r0, r1 000009: RETREG r0}
内嵌的js反汇编(简化后),功能为ecdsa签名验证:
function Function_0() { // name='global', args=0  function Function_4() { // name='', args=2    000000: CLOSURE      r2, 16 // _0x3c4bd8=r2    000001: CLOSURE      r3, 17 // _0x443985=r3    000002: CLOSURE      r4, 18 // _0x4653f8=r4    000003: CLOSURE      r5, 19 // _0x14ab88=r5    000004: CLOSURE      r6, 20 // _0x371323=r6    000005: CLOSURE      r7, 21 // _0x26acf4=r7    000006: CLOSURE      r8, 22 // _0x3e3825=r8    000007: CLOSURE      r9, 23 // _0x37288a=r9    000008: CLOSURE      r10, 24 // _0x6ea185=r10    000009: CLOSURE      r11, 25 // _0x389a22=r11    000010: CLOSURE      r12, 26 // _0x5b72da=r12    000011: CLOSURE      r13, 27 // _0x3f0439=r13    000012: GETVAR       r14, '_0x4b55' // _0x5aa897=r14    ...    000048: CSREG        r14, r38 // _0x5aa897=r14    000049: LDCONST      r40, '0x13'    000050: LDCONST      r41, 'Uev9'    000051: CALL0        2, r38 // _0x4b55('0x13','Uev9')='2b7874ef148937d1'    000052: LDCONST      r39, 'Nivrl'    000053: LDCONST      r40, '496412a7502c4cd5'    000054: LDCONST      r41, 'AxYnU'    000055: LDCONST      r42, 'c021a1277f8b7ee7'    000056: MPUTOBJ      r24, r25, 18 // Nivrl='496412a7502c4cd5', AxYnU='c021a1277f8b7ee7'    000057: LDREG        r15, r24 // _0x1d6a0f=r15    000058: CSREG        r2, r24 // _0x3c4bd8=r2    000059: LDREG        r26, r15 // _0x1d6a0f=r15    000060: CSREG        r14, r27 // _0x5aa897=r14    000061: LDCONST      r29, '0x93'    000062: LDCONST      r30, 'tglZ'    000063: CALL0        2, r27    000064: GETPROP_RR   r26, r26, r27    000065: LDINT        r27, 16    000066: CALL0        2, r24    000067: LDREG        r16, r24 // _0x45d09e=r16, BN('2b7874ef148937d1', 16)    000068: CSREG        r2, r25 // _0x3c4bd8=r2    000069: LDREG        r27, r15 // _0x1d6a0f=r15    000070: GETPROP_RC   r27, r27, 'Nivrl'    000071: LDINT        r28, 16    000072: CALL0        2, r25    000073: LDREG        r17, r25 // _0x158e32=r17, BN('496412a7502c4cd5', 16)    000074: CSREG        r2, r26 // _0x3c4bd8=r2    000075: LDCONST      r28, '4d8acf91aac0ba96'    000076: LDINT        r29, 16    000077: CALL0        2, r26    000078: LDREG        r18, r26 // _0x9114ff=r18    000079: CSREG        r2, r27 // _0x3c4bd8=r2    000080: LDCONST      r29, '79e9ac784679a36d'    000081: LDINT        r30, 16    000082: CALL0        2, r27    000083: LDREG        r19, r27 // _0x6d6511=r19, BN('79e9ac784679a36d', 16)    000084: CSREG        r2, r28 // _0x3c4bd8=r2    000085: LDCONST      r30, 'C021A12750820335'    000086: LDINT        r31, 16    000087: CALL0        2, r28    000088: LDREG        r20, r28 // _0xbe4903=r20, BN('C021A12750820335', 16)    000089: CSREG        r2, r29 // _0x3c4bd8=r2    000090: LDREG        r31, r15 // _0x1d6a0f=r15    000091: GETPROP_RC   r31, r31, 'AxYnU'    000092: LDINT        r32, 16    000093: CALL0        2, r29    000094: LDREG        r21, r29 // _0x160c05=r21, BN('c021a1277f8b7ee7', 16)    000095: CSREG        r2, r30 // _0x3c4bd8=r2    000096: LDINT        r32, 0    000097: CALL0        1, r30    000098: LDREG        r22, r30 // _0x14d425=r22    000099: CSREG        r2, r31 // _0x3c4bd8=r2    000100: LDINT        r33, 1    000101: CALL0        1, r31    000102: LDREG        r23, r31 // _0x3ac321=r23    000103: LDREG        r24, r1 // _0x1755c1=r1    000104: PUTPROP_CR   r24, 'gggggh', r2 // _0x3c4bd8=r2, gggggh=BN    000105: LDREG        r25, r1 // _0x1755c1=r1    000106: PUTPROP_CR   r25, 'bbccdde', r13 // _0x3f0439=r13, bbccdde=Function_27    000107: RETUNDEF    function Function_27(flag) { // name='_0x3f0439', args=1      000000: GETVAR       r1, '_0xb413'      000001: LDREG        r14, r0      000002: LDREG        r16, r14      000003: GETPROPC_RC  r15, r16, 'gte'      000004: GETVAR       r17, '_0x160c05'      000005: CALL0        1, r15      000006: IFTRUE_R     r15 // flag < _0x160c05      000007: JUMP         11      000008: NEWARR       0, r14      000009: LNOT         r14, r14      000010: RETREG       r14      000011: CSVAR_CR     r14, '_0x3c4bd8'      000012: LDCONST      r16, 'b520ee455c4e5c68'      000013: LDINT        r17, 16      000014: CALL0        2, r14      000015: LDREG        r2, r14 // r2=BN('b520ee455c4e5c68', 16)      000016: CSVAR_CR     r15, '_0x3c4bd8'      000017: LDCONST      r17, '8d2984eb2d7fd1ce'      000018: LDINT        r18, 16      000019: CALL0        2, r15      000020: LDREG        r3, r15 // r3=BN('8d2984eb2d7fd1ce', 16)      000021: GETVAR       r16, '_0x1d6a0f'      000022: LDREG        r18, r16      000023: GETPROPC_RC  r17, r18, 'kXpuM'      000024: GETVAR       r19, '_0x3c4bd8'      000025: LDCONST      r20, 130516937431      000026: LDINT        r21, 10      000027: CALL0        3, r17      000028: LDREG        r4, r17      000029: CSVAR_CR     r18, '_0x26acf4'      000030: LDREG        r20, r4      000031: CALL0        1, r18      000032: GETPROP_RC   r5, r18, 0 // r5=(BN('130516937431', 10)*G).x      000033: CSVAR_CR     r19, '_0x3c4bd8'      000034: CSREG        r1, r21      000035: LDCONST      r23, '0x42'      000036: CALL0        1, r21      000037: LDINT        r22, 16      000038: CALL0        2, r19      000039: LDREG        r6, r19 // r6=BN('4b43544632303230', 16)      000040: CSVAR_CR     r20, '_0x371323'      000041: LDREG        r22, r0      000042: GETVAR       r23, '_0x160c05'      000043: CALL0        2, r20      000044: LDREG        r7, r20 // r7=invert(flag, _0x160c05)      000045: CSVAR_CR     r21, '_0x4653f8'      000046: LDREG        r23, r6      000047: LDREG        r24, r7      000048: GETVAR       r25, '_0x160c05'      000049: CALL0        3, r21      000050: LDREG        r8, r21 // r8=mul(r6, r7, _0x160c05)      000051: CSVAR_CR     r22, '_0x4653f8'      000052: LDREG        r24, r5      000053: LDREG        r25, r7      000054: GETVAR       r26, '_0x160c05'      000055: CALL0        3, r22      000056: LDREG        r9, r22 // r9=mul(r5, r7, _0x160c05)      000057: CSVAR_CR     r23, '_0x5b72da'      000058: LDREG        r25, r2      000059: LDREG        r26, r3      000060: CALL0        2, r23      000061: LDREG        r10, r23 // r10=Point(r2, r3)      000062: CSVAR_CR     r24, '_0x5b72da'      000063: GETVAR       r26, '_0x9114ff'      000064: GETVAR       r27, '_0x6d6511'      000065: CALL0        2, r24      000066: LDREG        r11, r24 // r11=Point(_0x9114ff, _0x6d6511)      000067: CSVAR_CR     r25, '_0x389a22'      000068: CSVAR_CR     r27, '_0x443985'      000069: LDREG        r29, r11      000070: LDREG        r30, r8      000071: CALL0        2, r27 // r27=PointMul(r11, r8)      000072: CSVAR_CR     r28, '_0x443985'      000073: LDREG        r30, r10      000074: LDREG        r31, r9      000075: CALL0        2, r28 // r28=PointMul(r10, r9)      000076: CALL0        2, r25      000077: LDREG        r12, r25 // r12=PointAdd(r27, r28)      000078: CSVAR_CR     r26, '_0x3e3825'      000079: LDREG        r28, r12      000080: CALL0        1, r26      000081: LDREG        r13, r26 // r13=_0x3e3825(r12);      000082: LDREG        r14, r5      000083: LDREG        r16, r14      000084: GETPROPC_RC  r15, r16, 'eq'      000085: LDREG        r17, r13      000086: GETPROP_RC   r17, r17, 0      000087: CALL1        1, r15      000088: RETREG       r15 // return r5 == r13.x;      000089: RETUNDEF    }  }  function Function_5(flag) { // name='h', args=1    000000: CSVAR_CR     r2, 'gggggh'    000001: LDREG        r4, r0    000002: LDINT        r5, 16    000003: CALL0        2, r2    000004: LDREG        r1, r2    000005: CSVAR_CR     r2, 'bbccdde'    000006: LDREG        r4, r1    000007: CALL1        1, r2    000008: RETREG       r2 // return bbccdde(gggggh(flag, 16));    000009: RETUNDEF  }}
ecdsa
签名: r,sA: 2b7874ef148937d1B: 496412a7502c4cd5P: C021A12750820335Q: c021a1277f8b7ee7 (order)G: (4d8acf91aac0ba96, 79e9ac784679a36d)  (base)R: (b520ee455c4e5c68, 8d2984eb2d7fd1ce)  (pub)h: 4b43544632303230 (hash)k: 1E636A6AD7 (random)r: (k*G).x=4116EA4E6FE3A3C7  (sign.r)s: flag  (sign.s)
验证u: h/sv: r/sv = u *G + w *R = (h/s) *G + (r/s) * Rv == r
签名先算出私钥, d*G=R, d = 1EA97s = (h + r * d) / k = 2296dc2f09144713
--------------------------------x64 ECDLP Solver v0.2a by MR.HAANDIElliptic Curve defined by y^2 = x^3 + 3132382111026722769*x + 5288372372253723861over GF(13844523919740109621)
k*G=KG=[5587506512248486550,8784742180741292909]K=[13051693701788490856,10171807379008508366]Order(K)=13844523920529260263

Initializing rho solverk*G=KG=[5587506512248486550,8784742180741292909]K=[13051693701788490856,10171807379008508366]
k=125591
看完解析你会了吗?你还有不一样的解题思路吗?
实践出真知~速速动手自己做一遍,才算把知识装进脑子~
欢迎大家分享解题思路哦~

赛题回顾

2020 KCTF秋季赛 | 第一题点评及解题思路

出题战队:七星战队

2020 KCTF秋季赛 | 第二题设计及解题思路

出题战队:中娅之戒

2020 KCTF秋季赛 | 第三题点评及解题思路

出题战队:2019

2020 KCTF秋季赛 | 第四题点评及解题思路

出题战队:大灰狼爱喜羊羊

2020 KCTF秋季赛 | 第五题设计及解题思路

出题战队:金左手

2020 KCTF秋季赛 | 第六题设计及解题思路

出题团队:T.O.

2020 KCTF秋季赛 | 第七题设计及解题思路

出题团队:HU1战队

2020 KCTF秋季赛 | 第八题设计及解题思路

出题团队:BXS-iyzyi

2020 KCTF秋季赛 | 第九题设计及解题思路

出题团队:卑微菜鸡队

你的好友秀秀子拍了拍你

并请你点击阅读原文,查看题目解析


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458378121&idx=1&sn=5b06d2b9a784f233c8e776f1ee32d4d0&chksm=b180ef0386f766154eef61f6f0dafff0bd23057ac9565a2c2ef9c0bb79f6eee9dfe334601c93#rd
如有侵权请联系:admin#unsafe.sh