Risks (rev)

theres this pretty cool isa called riscv it sounds awesome.

We are given a binary which uses the riscv64 architecture. As such, we can run the binary using qemu-riscv64 -L /usr/riscv64-linux-gnu ./Risks

If you don't have qemu, you can install it using the following command:

sudo apt update
sudo apt install -y qemu-user libc6-arm64-cross libc6-riscv64-cross libc6-ppc64-cross

The binary accepts text, and checks if it's the flag. We get "nuh uh" for an invalid flag. The decompiled main code is as follows:

undefined8 main(void)
{
  char cVar1;
  long lVar2;
  undefined8 len;
  long buf;
  long local_20;
  long local_18;
  
  buf = 0;
  len = 0;
  print("whats the flag: ");
  /* buf becomes the address of the buffer, local_18 is no. of bytes read incl terminating byte */
  local_18 = getline(&buf,&len,_stdin);
  *(undefined *)(local_18 + -1 + buf) = 0;
  local_20 = buf;
  FUN_00101ad4(buf);
  FUN_00101346(local_20);
  FUN_00100c8c(local_20);
  FUN_00100786(local_20);
  lVar2 = FUN_00100690(buf);
  if ((lVar2 == 0x20) && (cVar1 = check(local_20), cVar1 == '\x01')) {
    puts("good job!");
    return 0;
  }
  puts("nuh uh");
  return 0;
}

The program accepts a line from stdin, and sets the last byte to be a null byte. FUN_00101ad4, FUN_00101346, FUN_00100c8c and FUN_00100786 are all functions which perform a combination of addition and XOR operations on the input buffer, which is treated as a long arr[4]. For example, FUN_00101ad4 contains the following code snippet:

void FUN_00101ad4(ulong *param_1)
{
  *param_1 = *param_1 + 0x75978f47ac76cf;
  param_1[1] = param_1[1] + 0xff889b2d229768ef;
  *param_1 = *param_1 ^ 0x76bf86ade5d5cc;
  param_1[2] = param_1[2] + 0x760f38b4bc69dc;
  *param_1 = *param_1 ^ 0x559f46365cee21;
  *param_1 = *param_1 + 0x5c6476bf0d4a19;
  *param_1 = *param_1 ^ 0xed41cda9780;
  param_1[2] = param_1[2] ^ 0x1e555c027a4e43;
  param_1[3] = param_1[3] + 0xfff29f96915a6e96;
  // truncated
  return;
}

FUN_00100690 then checks that the input is 32 bytes long. The check function contains the following code:

undefined8 check(long *param_1)
{
  undefined8 uVar1;
  
  if ((((*param_1 == 0x3167deae217139c1) && (param_1[1] == 0x6745aeaf0c9a62e5)) &&
      (param_1[2] == 0x62664d91c2da0c7b)) && (param_1[3] == 0x7ee01bea8defde65)) {
    uVar1 = 1;
  }
  else {
    uVar1 = 0;
  }
  return uVar1;
}

We want to fulfil all conditions in order to enter the if block, and have 1 returned. This will cause "good job" to be printed by main.

We can use the following Z3 script to perform the addition and XOR operations, and impose the 4 restrictions upon the arithmetic results.

import z3
# array of length 4, each element is a long (8 * 8 bits)
flag = [z3.BitVec(f"b{i}", 8 * 8) for i in range(4)]
new_flag = [flag[0], flag[1], flag[2], flag[3]]
solver = z3.Solver()

# ensure that all flag chars are ascii
for f in new_flag:
    for i in range(8):
        solver.add(0x21 <= z3.Extract((i + 1) * 8 - 1, i * 8, f))
        solver.add(z3.Extract((i + 1) * 8 - 1, i * 8, f) <= 0x7E)

# encryption 1
new_flag[0] = new_flag[0] + 0x75978f47ac76cf
new_flag[1] = new_flag[1] + 0xff889b2d229768ef
new_flag[0] = new_flag[0] ^ 0x76bf86ade5d5cc
new_flag[2] = new_flag[2] + 0x760f38b4bc69dc
new_flag[0] = new_flag[0] ^ 0x559f46365cee21
new_flag[0] = new_flag[0] + 0x5c6476bf0d4a19
new_flag[0] = new_flag[0] ^ 0xed41cda9780
new_flag[2] = new_flag[2] ^ 0x1e555c027a4e43
new_flag[3] = new_flag[3] + 0xfff29f96915a6e96
new_flag[0] = new_flag[0] ^ 0x4c46c321e8dc3d
new_flag[2] = new_flag[2] + 0x440d7b5dafb63c
new_flag[3] = new_flag[3] ^ 0x39549dd6e1299b
new_flag[0] = new_flag[0] + 0xff80a83276856f6b
new_flag[0] = new_flag[0] + 0x3869018f758dd0
new_flag[0] = new_flag[0] + 0xfff507f694ac1618
new_flag[0] = new_flag[0] + 0xffaef9a6a60ac41c
new_flag[2] = new_flag[2] ^ 0x4bb739ae97e2b2
new_flag[0] = new_flag[0] ^ 0xb9c189c728744
new_flag[3] = new_flag[3] ^ 0x63b60e480e2904
new_flag[1] = new_flag[1] + 0x70ea19e458d1dd
new_flag[0] = new_flag[0] ^ 0x1c380c9255dc4a
new_flag[0] = new_flag[0] ^ 0x72195b264896c6
new_flag[0] = new_flag[0] + 0xb58f5721006db
new_flag[1] = new_flag[1] + 0xfff1a19d465554d0
new_flag[1] = new_flag[1] + 0x45c8dee1a136cd
new_flag[1] = new_flag[1] + 0xff95aa1bc2ad9c07
new_flag[3] = new_flag[3] + 0xffed79b44c733cd6
new_flag[0] = new_flag[0] + 0x27d894eb9caa9b
new_flag[3] = new_flag[3] + 0xff9cb13f334ec53a
new_flag[3] = new_flag[3] + 0x3c2a0d8d36145a
new_flag[1] = new_flag[1] + 0x30a473f940b5dd
new_flag[2] = new_flag[2] + 0x7239ea8aa2bc49
new_flag[1] = new_flag[1] + 0x71e89e42b8b132
new_flag[1] = new_flag[1] + 0xff887455a5eb36fd
new_flag[2] = new_flag[2] + 0xffc07313a3962d72
new_flag[2] = new_flag[2] + 0xffcf924d075d2a72
new_flag[1] = new_flag[1] ^ 0x3707089012b521
new_flag[2] = new_flag[2] + 0x12b99b0e57e3bb
new_flag[1] = new_flag[1] + 0x3e897bb78bc162
new_flag[2] = new_flag[2] + 0xffc244c1f804fc9b
new_flag[3] = new_flag[3] ^ 0x21e211817f468b
new_flag[3] = new_flag[3] + 0x44c0052fcca332
new_flag[1] = new_flag[1] + 0x4f53af9faf8acf
new_flag[1] = new_flag[1] + 0x2fda660863a649
new_flag[1] = new_flag[1] + 0xffa9f06d0990b3ac
new_flag[2] = new_flag[2] + 0x2e93addef2df4f
new_flag[3] = new_flag[3] + 0x4531b2344b641b
new_flag[3] = new_flag[3] + 0xfff8e89a72f8e26c
new_flag[1] = new_flag[1] + 0x15c6da9bc36ed0
new_flag[2] = new_flag[2] ^ 0x738278f8599e2d
new_flag[1] = new_flag[1] ^ 0x44dd76d42e4513
new_flag[1] = new_flag[1] + 0xffb57183e089ceb4
new_flag[2] = new_flag[2] ^ 0x27972fbdfd287c
new_flag[0] = new_flag[0] ^ 0x7eb9039a2b6bf0
new_flag[2] = new_flag[2] + 0xffc75c67f5de1b31

# encryption 2
new_flag[0] = new_flag[0] ^ 0x131e29f760409
new_flag[1] = new_flag[1] + 0x23fe2dd7650a73
new_flag[1] = new_flag[1] + 0xfff70308e97acf79
new_flag[2] = new_flag[2] + 0xffb870f6f2950920
new_flag[0] = new_flag[0] ^ 0x58bd244826ef43
new_flag[2] = new_flag[2] + 0xffdc5874e8d03bbc
new_flag[1] = new_flag[1] + 0xffb3ce0944bbfc19
new_flag[0] = new_flag[0] ^ 0x38b3e1c4b3be14
new_flag[3] = new_flag[3] ^ 0x6de4b0dccee1f8
new_flag[2] = new_flag[2] + 0x48e99a2ccfbefa
new_flag[2] = new_flag[2] + 0x2803831f197314
new_flag[2] = new_flag[2] ^ 0x7fd3195c5e8bfb
new_flag[1] = new_flag[1] + 0x2311f9e5515a6d
new_flag[3] = new_flag[3] + 0x29e99994341bad
new_flag[2] = new_flag[2] + 0xffa46f41e698229f
new_flag[0] = new_flag[0] ^ 0x16097f9beb9df8
new_flag[2] = new_flag[2] ^ 0x58f5f5f9e64f77
new_flag[2] = new_flag[2] + 0xffce81bd3383de95
new_flag[0] = new_flag[0] + 0x1437a45ffed077
new_flag[2] = new_flag[2] + 0x4ec7609899b599
new_flag[3] = new_flag[3] + 0x77832406a422ee
new_flag[0] = new_flag[0] ^ 0xa299bfabd147f
new_flag[0] = new_flag[0] + 0xff9731d63e0a4ce9
new_flag[0] = new_flag[0] ^ 0x3ea0b669b87301
new_flag[0] = new_flag[0] ^ 0x7bc3ff2762eeb0
new_flag[0] = new_flag[0] + 0x2ff3559df23d95
new_flag[2] = new_flag[2] + 0xffb0934ca254c450
new_flag[0] = new_flag[0] + 0xff8b3b8d33d104e1
new_flag[3] = new_flag[3] ^ 0x2f268e55029508
new_flag[2] = new_flag[2] + 0xffe1c76d94c5b270
new_flag[3] = new_flag[3] ^ 0x5575918734e1cd
new_flag[0] = new_flag[0] + 0xffe368f50fe7ff81
new_flag[0] = new_flag[0] ^ 0x22b615021c1680
new_flag[0] = new_flag[0] + 0xff95c819c49f5170
new_flag[2] = new_flag[2] + 0x485e655976a7ee
new_flag[0] = new_flag[0] + 0x6f4847b022b253
new_flag[1] = new_flag[1] ^ 0x392622311d6f3d
new_flag[1] = new_flag[1] + 0xffb3096849dd7eb3
new_flag[3] = new_flag[3] ^ 0x6e8b5de620fa
new_flag[3] = new_flag[3] + 0x21d4322fefd286
new_flag[3] = new_flag[3] + 0xffe14e96454625c5
new_flag[3] = new_flag[3] ^ 0x4757d3b35495bb
new_flag[1] = new_flag[1] + 0xffc4845886e53673
new_flag[0] = new_flag[0] ^ 0x57617d2db4d1c4
new_flag[0] = new_flag[0] ^ 0x69bd97ec881da
new_flag[2] = new_flag[2] ^ 0x57ac6bbc11593
new_flag[2] = new_flag[2] ^ 0x5c2cbf22512aa3
new_flag[2] = new_flag[2] + 0x1860e298e3c0d5
new_flag[2] = new_flag[2] + 0xffe6f1b24728fb11
new_flag[0] = new_flag[0] + 0x4561b3931db109
new_flag[0] = new_flag[0] ^ 0x1a70a95138d536
new_flag[2] = new_flag[2] + 0x32ff8082367e19
new_flag[3] = new_flag[3] + 0xff99a53e605869f2
new_flag[0] = new_flag[0] + 0x1e359449108efb
new_flag[0] = new_flag[0] + 0xff9338172cb899f9
new_flag[0] = new_flag[0] + 0x33dbc3093cba9e
new_flag[1] = new_flag[1] + 0x7d005d760e8a00
new_flag[0] = new_flag[0] ^ 0x630abe094f2fcb
new_flag[2] = new_flag[2] ^ 0x5c693ca6ad4098
new_flag[2] = new_flag[2] ^ 0x1218c2c1fc6aab
new_flag[2] = new_flag[2] ^ 0x78d35fbb138c9c
new_flag[3] = new_flag[3] + 0x42dfb926a777d2
new_flag[3] = new_flag[3] ^ 0x3f60fd507495c5
new_flag[1] = new_flag[1] + 0x2cca6aa235fa04
new_flag[0] = new_flag[0] + 0x5a8e68db17f162
new_flag[0] = new_flag[0] + 0x1287bd45883bda
new_flag[0] = new_flag[0] + 0xffe7b46bbeb822c6
new_flag[3] = new_flag[3] + 0x5234b2a7901fd8
new_flag[3] = new_flag[3] + 0xa856e4c03b946
new_flag[1] = new_flag[1] ^ 0x6312ec05f527a4
new_flag[1] = new_flag[1] + 0x46ce8a9c234e2f
new_flag[3] = new_flag[3] + 0x171cfaebba97ed

# encryption 3
new_flag[2] = new_flag[2] ^ 0x21552380a54ebd
new_flag[2] = new_flag[2] ^ 0x217fe5a723014c
new_flag[2] = new_flag[2] + 0xff929930c56e6594
new_flag[2] = new_flag[2] ^ 0x7eb96f8929799a
new_flag[3] = new_flag[3] + 0x67d0ff39897513
new_flag[3] = new_flag[3] + 0x26a2f35c92df10
new_flag[2] = new_flag[2] + 0xffd5d8a901dbebd6
new_flag[2] = new_flag[2] + 0xad9fcf45aef6
new_flag[2] = new_flag[2] + 0xffc53d1702ef8aa8
new_flag[0] = new_flag[0] + 0x591ac5d1939c8b
new_flag[2] = new_flag[2] ^ 0x33d94a84565532
new_flag[2] = new_flag[2] ^ 0x308afb7e01e13e
new_flag[3] = new_flag[3] + 0xffb48db7039082e1
new_flag[2] = new_flag[2] ^ 0x55662e74858cf1
new_flag[3] = new_flag[3] + 0xffa5b828a6179210
new_flag[1] = new_flag[1] ^ 0x1638c6225c560d
new_flag[2] = new_flag[2] ^ 0x40641fcdaf2a6d
new_flag[0] = new_flag[0] + 0x1907586d8aaec6
new_flag[1] = new_flag[1] ^ 0x2ac0e1d87fbfd3
new_flag[0] = new_flag[0] + 0x4903ecf455fa05
new_flag[1] = new_flag[1] + 0xff84efef75a89283
new_flag[2] = new_flag[2] ^ 0x575e02c2ec2e98
new_flag[2] = new_flag[2] ^ 0x5686c924044043
new_flag[0] = new_flag[0] + 0xffa75728515de781
new_flag[0] = new_flag[0] + 0x6c40d33a5de8b4
new_flag[0] = new_flag[0] + 0xffae776809930118
new_flag[1] = new_flag[1] + 0x77250c081305ce
new_flag[2] = new_flag[2] + 0xffeff0d64a3fb770
new_flag[3] = new_flag[3] + 0x1106386668917b
new_flag[2] = new_flag[2] ^ 0x2a958285eaabc6
new_flag[1] = new_flag[1] + 0x17e82fdc4bb7e6
new_flag[2] = new_flag[2] + 0x6e5b6deacda2b3
new_flag[1] = new_flag[1] + 0xffe4362cd469721d
new_flag[1] = new_flag[1] ^ 0x46a8ddb8e7831e
new_flag[0] = new_flag[0] + 0x5ef639bb0d96fc
new_flag[3] = new_flag[3] ^ 0x540dd0d8537808
new_flag[3] = new_flag[3] + 0xffd7468d44d84bfc
new_flag[2] = new_flag[2] + 0xffb5048de8c6e26a
new_flag[0] = new_flag[0] ^ 0x457b282105f5ff
new_flag[1] = new_flag[1] ^ 0x2eff779ebf04ee
new_flag[1] = new_flag[1] ^ 0x282c4c9602a8d1
new_flag[0] = new_flag[0] ^ 0x5892a99ecd56db
new_flag[1] = new_flag[1] + 0x7306fd8fb4ac48
new_flag[3] = new_flag[3] + 0x4b3f6ca9126599
new_flag[3] = new_flag[3] + 0xffed5514bbd0b395
new_flag[0] = new_flag[0] + 0x19b2a80c1ebde0
new_flag[2] = new_flag[2] ^ 0x34ab995333d7bc
new_flag[0] = new_flag[0] ^ 0x4b803835540e77
new_flag[2] = new_flag[2] ^ 0x4aaf3dd459117d
new_flag[3] = new_flag[3] ^ 0x45b9bf142dd7b9
new_flag[0] = new_flag[0] + 0xffdae06e2a1c7254
new_flag[1] = new_flag[1] + 0xff805d1980ad21aa
new_flag[0] = new_flag[0] + 0xff8aba0c42d40896
new_flag[0] = new_flag[0] + 0x425422cc59e30
new_flag[0] = new_flag[0] + 0x235f71339ac927
new_flag[2] = new_flag[2] + 0xffb282c744cb6616
new_flag[2] = new_flag[2] + 0xffa61489eb15d360
new_flag[0] = new_flag[0] ^ 0x8db3daacc3ff9
new_flag[2] = new_flag[2] ^ 0x97368bc6e7d41
new_flag[3] = new_flag[3] ^ 0x86c96f6b4510f
new_flag[2] = new_flag[2] ^ 0x1951f11deeb2fa
new_flag[1] = new_flag[1] + 0x5dc2de99056b51
new_flag[2] = new_flag[2] + 0xffb654da8cc4cb5f

# encryption 4
new_flag[3] = new_flag[3] + 0xffdb0267f30481de
new_flag[0] = new_flag[0] + 0xd349975ed71ce
new_flag[3] = new_flag[3] + 0x396b3ec36373cc
new_flag[3] = new_flag[3] ^ 0x2d2d96a9d4da30
new_flag[2] = new_flag[2] ^ 0x656498272858da
new_flag[2] = new_flag[2] + 0xffb3ad5ab10bc1f3
new_flag[0] = new_flag[0] + 0x23b2f30be0e9ab
new_flag[0] = new_flag[0] + 0xff99bef8c799559b
new_flag[0] = new_flag[0] + 0xffe049bda2d90572
new_flag[2] = new_flag[2] + 0xff9d4568f99d45eb
new_flag[2] = new_flag[2] ^ 0x26ed48b4153eb0
new_flag[2] = new_flag[2] ^ 0x1af75e7b5b8c5f
new_flag[2] = new_flag[2] + 0xffe9fc2941b7bd92
new_flag[1] = new_flag[1] ^ 0x4b4b690f995f73
new_flag[0] = new_flag[0] + 0xffa3bcbff21dd191
new_flag[2] = new_flag[2] ^ 0x6feb10d533c4b1
new_flag[1] = new_flag[1] + 0xffb8a8e39fec3250
new_flag[2] = new_flag[2] + 0xffdb2496d81b4293
new_flag[0] = new_flag[0] + 0xffb778b645f31de9
new_flag[0] = new_flag[0] ^ 0x531e0306cda7a9
new_flag[2] = new_flag[2] ^ 0x3521f52cd98bf4
new_flag[1] = new_flag[1] + 0xff880d1e8951a4a0
new_flag[2] = new_flag[2] + 0x3858d7d314a793
new_flag[2] = new_flag[2] + 0xffd7c92ed6f1e27a
new_flag[1] = new_flag[1] + 0x37f1e8ac57fd21
new_flag[2] = new_flag[2] + 0x794d667495ec53
new_flag[0] = new_flag[0] + 0xf80ea376dfe9c
new_flag[2] = new_flag[2] + 0x7077ef6357df45
new_flag[1] = new_flag[1] + 0xfffe413b9b12d6da
new_flag[3] = new_flag[3] + 0x562536f5f8bacf
new_flag[3] = new_flag[3] + 0xff9f07032cf0845d
new_flag[0] = new_flag[0] ^ 0x4ba91df7d06027
new_flag[0] = new_flag[0] + 0xfff6ae6bcf2ebbbc
new_flag[3] = new_flag[3] ^ 0x55cdaa7dfb2afc
new_flag[3] = new_flag[3] + 0x318ce149b3a1fc
new_flag[3] = new_flag[3] + 0xffd5d916adc11571
new_flag[0] = new_flag[0] + 0xffc3560b3c7ef5e9
new_flag[1] = new_flag[1] + 0xa8c0f5e148a9e
new_flag[2] = new_flag[2] ^ 0x7b607330d80f26
new_flag[0] = new_flag[0] ^ 0x3c139ff1892f4f
new_flag[1] = new_flag[1] + 0x1f63d4725b825e
new_flag[3] = new_flag[3] + 0x6be58b7a89dd9d
new_flag[1] = new_flag[1] ^ 0x67b81b10716f5
new_flag[1] = new_flag[1] + 0x70efa9f526c942
new_flag[3] = new_flag[3] ^ 0x411eb7ecadc3cb
new_flag[3] = new_flag[3] ^ 0x250c9395e3a054
new_flag[0] = new_flag[0] + 0x78f186d15f1e3b

# check
solver.add(z3.And(new_flag[0] == 0x3167deae217139c1, new_flag[1] == 0x6745aeaf0c9a62e5, new_flag[2] == 0x62664d91c2da0c7b, new_flag[3] == 0x7ee01bea8defde65))

if solver.check() != z3.sat:
    print("No solution")
    exit()

m = solver.model()
# we should solve for flag instead of new_flag, since each f in 
# new_flag is of type BitVecRef and not BitVec.
nums = "".join([hex(m[f].as_long())[2:] for f in flag][::-1])
n = bytes.fromhex(nums)[::-1]
print(n) # akasec{1n_my_b4g_0n3_s3c0nd_0n3}

Last updated