├── LICENSE ├── README.md ├── examples └── phpinfo.php └── phpfuck.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ꌗᖘ꒒ꀤ꓄꒒ꀤꈤꍟ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHPFuck: ([+.^]) 2 | Using only 7 different characters to write and execute php. 3 | 4 | Only support PHP 7+ currently. 5 | 6 | ## Example Code 7 | The following source will execute `phpinfo();`: 8 | 9 | ```php 10 | 47 | ``` 48 | 49 | ## Usage 50 | 51 | ``` 52 | usage: phpfuck.py [-h] [-O FILE] [-P] [-E {assert,create_function}] code 53 | 54 | positional arguments: 55 | code any string to encode. 56 | 57 | optional arguments: 58 | -h, --help show this help message and exit 59 | -O FILE, --output-file FILE 60 | write encoded string into some file. 61 | -P, --plain-string encode as plain string (without eval it). 62 | -E {assert,create_function}, --eval {assert,create_function} 63 | choose eval mode. (`assert` mode only support PHP < 7.1) 64 | ``` 65 | 66 | You can just use it like this: `python3 phpfuck.py "system('id');"` 67 | 68 | ### Arguments 69 | - code (required) 70 | - Any string or php code to encode. 71 | - -O, --output-file 72 | - Write encoded string into some file. 73 | - -P, --plain-string 74 | - Encode as plain string (without eval it). 75 | - With this argument, I will not wrap your code into `assert` or `create_function` to eval. 76 | - -E, --eval 77 | - You can choose your eval mode! 78 | - `create_function` mode (default) 79 | - `create_function('', YOUR_CODE)();` 80 | - `assert` mode 81 | - Only support PHP < 7.1 (=7.0.x). 82 | - `assert( '(function(){ YOUR_CODE; return 1; })()' );` 83 | 84 | ## TODO 85 | - [x] Support characters other than ASCII range. 86 | - [ ] Don't use deprecated feature. (`create_function` has been DEPRECATED) 87 | - [x] Web interface. (https://splitline.github.io/PHPFuck/) 88 | - [ ] Compatible with PHP 8 89 | - Maybe string mode only, since the `create_function` has been removed from PHP 8 :( 90 | -------------------------------------------------------------------------------- /examples/phpinfo.php: -------------------------------------------------------------------------------- 1 | 38 | -------------------------------------------------------------------------------- /phpfuck.py: -------------------------------------------------------------------------------- 1 | # PHPFuck: ([+.^]) 2 | 3 | import string 4 | from argparse import ArgumentParser 5 | 6 | 7 | class PHPFuck(): 8 | def __init__(self): 9 | # simple constant 10 | arr_str = "[].[]" # "ArrayArray" 11 | zero = "([]^[])" 12 | one = "([]^[[]])" 13 | 14 | # generate digits 15 | nums = [zero, one] 16 | for i in range(2, 10): 17 | nums.append('+'.join([nums[1]]*i)) 18 | 19 | self.nums = nums 20 | # using `Aray0123456789` & xor to generate printable ascii char 21 | self.char_mapping = { 22 | '\t': f'{nums[1]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 23 | '\n': f'{nums[2]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 24 | '\x0b': f'({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 25 | '\x0c': f'{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 26 | '\r': f'{nums[5]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 27 | ' ': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]', 28 | '!': f'{nums[2]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 29 | '"': f'{nums[1]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 30 | '#': f'{nums[0]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 31 | '$': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]', 32 | '%': f'{nums[1]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]', 33 | '&': f'{nums[5]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 34 | "'": f'{nums[4]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 35 | '(': f'{nums[0]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 36 | ')': f'{nums[1]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 37 | '*': f'{nums[2]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 38 | '+': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 39 | ',': f'{nums[4]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 40 | '-': f'{nums[5]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 41 | '.': f'{nums[6]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 42 | '/': f'{nums[7]}.[][[]]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 43 | '0': f'{nums[0]}.[][[]]', 44 | '1': f'{nums[1]}.[][[]]', 45 | '2': f'{nums[2]}.[][[]]', 46 | '3': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[1]}]', 47 | '4': f'{nums[4]}.[][[]]', 48 | '5': f'{nums[5]}.[][[]]', 49 | '6': f'{nums[6]}.[][[]]', 50 | '7': f'{nums[7]}.[][[]]', 51 | '8': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 52 | '9': f'{nums[2]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 53 | ':': f'{nums[1]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 54 | ';': f'{nums[0]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 55 | '<': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 56 | '=': f'{nums[1]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[4]}]', 57 | '>': f'{nums[5]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 58 | '?': f'{nums[4]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 59 | '@': f'{nums[2]}.[][[]]^({arr_str})[{nums[1]}]', 60 | 'A': f'({arr_str})[{nums[0]}]', 61 | 'B': f'{nums[0]}.[][[]]^({arr_str})[{nums[1]}]', 62 | 'C': f'{nums[1]}.[][[]]^({arr_str})[{nums[1]}]', 63 | 'D': f'{nums[1]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]', 64 | 'E': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]', 65 | 'F': f'{nums[4]}.[][[]]^({arr_str})[{nums[1]}]', 66 | 'G': f'{nums[5]}.[][[]]^({arr_str})[{nums[1]}]', 67 | 'H': f'{nums[1]}.[][[]]^({arr_str})[{nums[4]}]', 68 | 'I': f'{nums[0]}.[][[]]^({arr_str})[{nums[4]}]', 69 | 'J': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]', 70 | 'K': f'{nums[2]}.[][[]]^({arr_str})[{nums[4]}]', 71 | 'L': f'{nums[5]}.[][[]]^({arr_str})[{nums[4]}]', 72 | 'M': f'{nums[4]}.[][[]]^({arr_str})[{nums[4]}]', 73 | 'N': f'{nums[7]}.[][[]]^({arr_str})[{nums[4]}]', 74 | 'O': f'{nums[6]}.[][[]]^({arr_str})[{nums[4]}]', 75 | 'P': f'{nums[1]}.[][[]]^({arr_str})[{nums[3]}]', 76 | 'Q': f'{nums[0]}.[][[]]^({arr_str})[{nums[3]}]', 77 | 'R': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 78 | 'S': f'{nums[2]}.[][[]]^({arr_str})[{nums[3]}]', 79 | 'T': f'{nums[5]}.[][[]]^({arr_str})[{nums[3]}]', 80 | 'U': f'{nums[4]}.[][[]]^({arr_str})[{nums[3]}]', 81 | 'V': f'{nums[7]}.[][[]]^({arr_str})[{nums[3]}]', 82 | 'W': f'{nums[6]}.[][[]]^({arr_str})[{nums[3]}]', 83 | 'X': f'{nums[2]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 84 | 'Y': f'({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 85 | 'Z': f'{nums[0]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 86 | '[': f'{nums[1]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 87 | '\\': f'{nums[1]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 88 | ']': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 89 | '^': f'{nums[4]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 90 | '_': f'{nums[5]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 91 | '`': f'{nums[0]}.[][[]]^{nums[1]}.[][[]]^({arr_str})[{nums[3]}]', 92 | 'a': f'({arr_str})[{nums[3]}]', 93 | 'b': f'{nums[1]}.[][[]]^{nums[2]}.[][[]]^({arr_str})[{nums[3]}]', 94 | 'c': f'{nums[0]}.[][[]]^{nums[2]}.[][[]]^({arr_str})[{nums[3]}]', 95 | 'd': f'{nums[1]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[3]}]', 96 | 'e': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[3]}]', 97 | 'f': f'{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]', 98 | 'g': f'{nums[2]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[3]}]', 99 | 'h': f'{nums[1]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 100 | 'i': f'{nums[0]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 101 | 'j': f'({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 102 | 'k': f'{nums[2]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 103 | 'l': f'{nums[5]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 104 | 'm': f'{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 105 | 'n': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[1]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 106 | 'o': f'{nums[6]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[3]}]^({arr_str})[{nums[4]}]', 107 | 'p': f'{nums[1]}.[][[]]^({arr_str})[{nums[0]}]', 108 | 'q': f'{nums[0]}.[][[]]^({arr_str})[{nums[0]}]', 109 | 'r': f'({arr_str})[{nums[1]}]', 110 | 's': f'{nums[2]}.[][[]]^({arr_str})[{nums[0]}]', 111 | 't': f'{nums[5]}.[][[]]^({arr_str})[{nums[0]}]', 112 | 'u': f'{nums[4]}.[][[]]^({arr_str})[{nums[0]}]', 113 | 'v': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[1]}]', 114 | 'w': f'{nums[6]}.[][[]]^({arr_str})[{nums[0]}]', 115 | 'x': f'{nums[0]}.[][[]]^{nums[1]}.[][[]]^({arr_str})[{nums[4]}]', 116 | 'y': f'({arr_str})[{nums[4]}]', 117 | 'z': f'{nums[1]}.[][[]]^{nums[2]}.[][[]]^({arr_str})[{nums[4]}]', 118 | '{': f'{nums[0]}.[][[]]^{nums[2]}.[][[]]^({arr_str})[{nums[4]}]', 119 | '|': f'{nums[1]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[4]}]', 120 | '}': f'{nums[0]}.[][[]]^{nums[4]}.[][[]]^({arr_str})[{nums[4]}]', 121 | '~': f'{nums[4]}.[][[]]^({arr_str})[{nums[0]}]^({arr_str})[{nums[1]}]^({arr_str})[{nums[4]}]'} 122 | 123 | def encode(self, code, eval_mode=None): 124 | def clean_code(code): 125 | return code.replace('\n', '').replace(' ', '') 126 | 127 | def basic_encode(code): 128 | return '.'.join([f"({self.char_mapping[c] if c in self.char_mapping else fix_missing_char(c)})" for c in code]) 129 | 130 | def encode_number(num): 131 | return f"{self.nums[0]}+({'.'.join([self.nums[int(n)] for n in str(num)])})" 132 | 133 | def fix_missing_char(char, compatiable=True): 134 | # to compatiable with PHP < 7.2.0: `mb_chr` only support PHP >= 7.2.0 135 | if compatiable: 136 | str_getcsv = basic_encode("str_getcsv") 137 | mb_chr = basic_encode('IntlChar,chr') 138 | char_code = encode_number(ord(char)) 139 | return f"({str_getcsv})({mb_chr})({char_code})" 140 | else: 141 | return f"({basic_encode('mb_chr')})({basic_encode(str(ord(char)))})" 142 | 143 | if eval_mode == 'create_function': 144 | code = code.replace('"', '""') 145 | 146 | code = basic_encode(code) 147 | 148 | if not eval_mode: 149 | return code 150 | 151 | elif eval_mode == 'create_function': 152 | create_function = basic_encode("create_function") 153 | str_getcsv = basic_encode("str_getcsv") 154 | comma = basic_encode(",") 155 | quote = basic_encode('"') 156 | 157 | """ 158 | 1. create_function(...str_getcsv(',"YOUR_CODE"') ) 159 | 2. create_function(...['', 'YOURCODE']) 160 | 3. create_function('', 'YOURCODE') 161 | """ 162 | 163 | eval_code = f"""({create_function})( 164 | ...({str_getcsv})({comma}.{quote}.{code}.{quote}) 165 | )() 166 | """ 167 | 168 | elif eval_mode == 'assert': # only support PHP < 7.1 169 | assert_func = basic_encode('assert') 170 | prefix = basic_encode('(function(){') 171 | postfix = basic_encode(';return 1;})()') 172 | eval_code = f""" 173 | ({assert_func})( 174 | ({prefix}).({code}).({postfix}) 175 | ) 176 | """ 177 | 178 | return clean_code(eval_code) 179 | 180 | 181 | if __name__ == "__main__": 182 | parser = ArgumentParser() 183 | parser.add_argument("code", help="any string to encode.") 184 | parser.add_argument("-O", "--output-file", dest="file", 185 | help="write encoded string into some file.") 186 | parser.add_argument("-P", "--plain-string", dest="plain", action='store_true', 187 | help="encode as plain string (without eval it).") 188 | parser.add_argument("-E", "--eval", dest="eval", 189 | choices=['assert', 'create_function'], default='create_function', 190 | help="choose eval mode. (`assert` mode only support PHP < 7.1)") 191 | args = parser.parse_args() 192 | 193 | code = args.code 194 | 195 | phpfuck = PHPFuck() 196 | 197 | if args.plain: 198 | encoded = phpfuck.encode(code) 199 | assert(set(encoded) <= set('([+.^])')) 200 | else: 201 | encoded = phpfuck.encode(code, args.eval) 202 | assert(set(encoded[:-1]) <= set('([+.^])')) 203 | encoded = "\n" 204 | 205 | if args.file: 206 | open(args.file, 'w').write(encoded) 207 | else: 208 | print(encoded) 209 | 210 | if args.plain: 211 | print(f"Output as plain string, without eval it.") 212 | else: 213 | print(f"Using `{args.eval}` mode to eval.") 214 | 215 | print(len(encoded), "chars.") 216 | --------------------------------------------------------------------------------