My teammate (nobodyisnobody and macz) and I had a quick look on these challenges, but we did not have time to flag anything but the first one during the CTF.
After Happy Fun Binary Pt.1, we have a library called binary_of_ballas.so. The binary dlopens the library and calls the symbol "foyer". We can simulate that with this simple wrapper:```// gcc -m32 wrapper.c -o wrap -ldl#include <stdlib.h>#include <dlfcn.h>int main(){    void *h;    void *(*f)();    h = dlopen("./binary_of_ballas.so",2);    f = (void *(*)())dlsym(h,"foyer");    f();    dlclose(h);    return 0;}```
After some reversing work, the foyer function may look like this:```void foyer(void){    int len;    int fd;    char buf1 [64];    char buf2 [192];    char command [256];
    puts("You emerge into a grand and extravegant foyer. While sparsely furnished, intricately crafted code decorates every square inch of the walls and ceiling. In the center of the room lies a grand structure, carved into which are three slots. The three slots feed into a large chest in the middle of the room. On the far side of the room lies 2 semi-circular doorways leading into darkness.\n");    do {        fgets(buf1,0x40,stdin);        if (strcmp(buf1,"examine the doormat\n") == 0) {            printf("You look down, and are surprised to see a welcome mat beneath your feet. On it reads \"%s\". That was easy!\n","flag{yes_this_is_all_one_big_critical_role_reference}");        }        if (strcmp(buf1,"examine the treasure chest\n") == 0) {            puts("Inscribed on the chest is the message: \"Welcome to my halls, adventurer. I have left my worldly belongings in this chest, to be claimed by one worthy enough to inherit my mantle. In my halls you will find three flags. These flags, along with the contents of this chest, will prove to be more valuable than you can imagine. I wish you luck in your attempts to decipher my puzzles\"\n");        }        if (strcmp(buf1,"open the treasure chest\n") == 0) {
            puts("You go to open the chest, and see 3 slots engraved into the lock. You gather that you need to place your 3 flags in these slots to open it.\nfirst flag:\n");            fgets(buf1,0x40,stdin);            len = strlen(buf1);            buf1[len-1] = 0;            strcat(buf2,buf1);
            puts("second flag: ");            fgets(buf1,0x40,stdin);            len = strlen(buf1);            buf1[len-1] = 0;            strcat(buf2,buf1);
            puts("third flag: ");            fgets(buf1,0x40,stdin);            len = strlen(buf1);            buf1[len-1] = 0;            strcat(buf2,buf1);
            sprintf(command,"unzip -P %s chest",buf2);            fd = fopen("chest","w");            fwrite(chest,1,0xf6,fd);            fclose(fd);            system(command);        }        if (strcmp(buf1,"enter the first doorway\n") == 0) {            puts("You step through the doorway...\n");            chall_1();        }        if (strcmp(buf1,"enter the second doorway\n") == 0) {            puts("You step through the doorway...\n");            chall_2();        }    } while( true );}```
The first flag is in sight. To get the second flag, we need to reverse the the function chall_1. This is not an easy task as it involves extended precision float of 80 bits and some basic structures:```struct what {    char c,         // + 0x0    float80 f1,     // + 0x4    float80 f2      // + 0x10} //(size = 0x1c = 28)
struct hell {    char c,         // + 0x0    float80 f       // + 0x4} //(size = 0x10 = 16)```
The function initializes a table of five "what" from the values of an another table of five "hell" stored in the library data. It defines five contiguous intervals for the five letters: p, b, e, }, _
A python implementation may look like this:```import gmpy2from gmpy2 import mpfr as fgmpy2.get_context().precision=100
def float80(x):    if x & (1<<79):        s = f(-1.0)    else:        s = f(1.0)    e = (x & ((1<<79)-1)) >> 64    m = x & ((1<<64)-1)    if m & 0x8000000000000000:        i = f(1.0)    else:        i = f(0.0)    m &= 0x7FFFFFFFFFFFFFFF    res = gmpy2.div(f(m),f(1<<63))    res = gmpy2.add(res,i)    res = gmpy2.mul(res,f(2**(e - 16383)))    return gmpy2.mul(s,res) def frfc(c, wth, five):    for i in range(5):        if c == wth[i][0]:            return wth[i]    exit("ooops")
def encode(f1, f2, flag, five):    global wtf    tmp_float = f1;    for i in range(5):        wtf[i][1] = tmp_float        wtf[i][2] = tmp_float + (gmpy2.add(tmp_float, gmpy2.mul(gmpy2.sub(f2, f1), table[i][1]))f2- f1) * table[i][1]        tmp_float = wtf[i][2]    debugWTF()    wha = frfc(flag[0], wtf, five);    if len(flag) == 1 :        res = gmpy2.div(gmpy2.add(wha[1],wha[2]), A)    else:        res = encode(wha[1], wha[2], flag[1:], five)    return res
def debugWTF():    for w in wtf:        print( "%s | %.20f | %.20f | delta: %.20f" %(w[0], w[1],w[2],w[2]-w[1]) )    print()
# init table @ 0xf7fcc0a0table = []table.append(("p", float80(0x3ffd86bca50000000000)))table.append(("b", float80(0x3ffcd794210000000000)))table.append(("e", float80(0x3ffdbca1ad0000000000)))table.append(("}", float80(0x3ff9d794a70000000000)))table.append(("_", float80(0x3ffc86bca50000000000)))
# init float used in encode A = float80(0x40008000000000000000) # = 2.0
# init values of wtfwtf = [["",0.0,0.0] for i in range(5)]tmpf = f(0.0)for i in range(5):    wtf[i][0] = table[i][0]    wtf[i][1] = tmpf    tmpf = gmpy2.add(tmpf, table[i][1])    wtf[i][2] = tmpf
print(encode(f(0.0),f(1.0),"beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep}",5))```
We see that the encode function is called recursively for each letter of the flag. Each time, the intervals are narrowed to match the previous chosen interval. When entering the function chal_1, we are given a float ~ 0.406562. Let's try to get a flag that gives this value, by selecting the letter corresponding to the interval that matches this initial value:```import gmpy2from gmpy2 import mpfr as fgmpy2.get_context().precision=100
def float80(x):    if x & (1<<79):        s = f(-1.0)    else:        s = f(1.0)    e = (x & ((1<<79)-1)) >> 64    m = x & ((1<<64)-1)    if m & 0x8000000000000000:        i = f(1.0)    else:        i = f(0.0)    m &= 0x7FFFFFFFFFFFFFFF    res = gmpy2.div(f(m),f(1<<63))    res = gmpy2.add(res,i)    res = gmpy2.mul(res,f(2**(e - 16383)))    return gmpy2.mul(s,res) def frfc(c, wth, five):    for i in range(5):        if c == wth[i][0]:            return wth[i]    exit("ooops")
def narrowWTF(i):    global wtf    f1 = wtf[i][1]    f2 = wtf[i][2]    tmp_float = f1;    for i in range(5):        wtf[i][1] = tmp_float        wtf[i][2] = gmpy2.add(tmp_float, gmpy2.mul(gmpy2.sub(f2, f1), table[i][1]))        tmp_float = wtf[i][2]
def debugWTF():    for w in wtf:        print( "%s | %.20f | %.20f | delta: %.20f" %(w[0], w[1],w[2],w[2]-w[1]) )    print() # init table @ 0xf7fcc0a0table = []table.append(("p", float80(0x3ffd86bca50000000000)))table.append(("b", float80(0x3ffcd794210000000000)))table.append(("e", float80(0x3ffdbca1ad0000000000)))table.append(("}", float80(0x3ff9d794a70000000000)))table.append(("_", float80(0x3ffc86bca50000000000)))
# init float used in encode A = float80(0x40008000000000000000) # = 2.0
# init value of thefloattarget = float80(0x3ffdd028f580b8df35b3)
# init values of wtfwtf = [["",0.0,0.0] for i in range(5)]tmpf = f(0.0)for i in range(5):    wtf[i][0] = table[i][0]    wtf[i][1] = tmpf    tmpf = gmpy2.add(tmpf, table[i][1])    wtf[i][2] = tmpf
# get the  flagflag = "flag{"while 1:    goodi = -1    for i,w in enumerate(wtf):        if w[1] <= target < w[2]:            flag += w[0]            print( flag )            goodi = i            break    if goodi < 0:        print( flag )        print( target )        debugWTF()        exit("oof")     elif flag[-1] == "}":        print( flag )        exit()     narrowWTF(goodi)```
This gives us the flag: flag{beep_beeep_bbbeeep_beeeeppppp}