top | item 39158325

(no title)

joosters | 2 years ago

The meaning of ^ and $ in perl regexes can be altered by modifiers at the end of the regex. A 'multi-line' regex, with a /m at the end, makes them match the start and end of any line.

discuss

order

jwilk|2 years ago

The code doesn't use /m. So indeed the problem is that $ will match before \n at the end of the string the Perl interpreter is working with, which is not the whole thing containing the payload.

jodrellblank|2 years ago

I've just worked through it to understand it; it's a more subtle exploit than I thought. My above comment about $ being end-of-line is wrong, the above comment saying you need the /m modifier for that to happen is correct.

In case anyone cares, the bug matches <backslash> <newline> <quote> then the regex in question matches <backslash> <newline> and the code logic is that one backslash must be escaping the next character from the input, but instead of adding on the next character it always adds a quote - after searching for a quote the next character must be a quote, right? But it wasn't, it was a newline, which was missed because of $ behaviour with newline at the end of a string. That acts to shift the quote one to the left <backslash> <quote> <newline> and now that makes an escaped quote which won't break eval() and the loop carries on and reads in the exploit text up to the real end quote.

----

Details: the Perl code takes this pattern in the input (the quotes are part of the input, in the file data):

    "a\
    ""
six characters, describing a quoted string of four characters: <a> <backslash> <newline> <quote>

The Perl code finds the string starting quote and moves past it, and sets $tok empty to hold the quoted string content. Then it searches for the next quote (not the last, the next):

    last Tok unless $$dataPt =~ /"/sg;
    
This will match at the quote after the newline. Then it substrings from the saved opening quote position to 1 before the found quote. So the substring includes the newline char:

    # the closing quote position. (not including the quote).
    $tok .= substr($$dataPt, $pos, pos($$dataPt)-1-$pos);
That gets <a> <backslash> <newline> and not the following <quote> <quote>

Then it does the odd-number-of-backslashes test on the substring <a> <backslash> <newline>:

    last unless $tok =~ /(\\+)$/ and length($1) & 0x01;
And the regex matches for <backslash> <newline> instead of the intended <backslash> ENDOFSTRING so the code thinks there is an escaped character. It doesn't add the next character from the string into the token, it assumes the escaped character must be a quote and always adds a quote to $tok.

    $tok .= '"';    # quote is part of the string
Effectively shifting the input quote to the other side of the newline, from:

    "a\
    ""
to

    "a\"
    "
and in the exploit case:

    "a\
    "exploit code"
to

    "a\"
    exploit code"
Then the inner loop runs again and finds the <exploit code to closing quote> text and adds that on to $tok. Now there's a string with an escaped quote and some exploit code.