I agree that this might not necessarily be a problem in practice or in theory.  
Just canvassing opinion of others with more knowledge about this then I do.

From: Tommy Murphy <[email protected]>
Sent: Monday, July 19, 2021 5:30 PM
To: OpenOCD <[email protected]>; Ooi, Cinly 
<[email protected]>
Subject: Re: Potential NULL byte injection

Thanks but I still don't really get it.
The commands that you mention do not exist in openocd.
And the user is in full control of the scripts passed to openocd so would have 
to allow them to contain the null but injection themselves.
I still don't see how this is necessarily a problem in practice or maybe even 
in theory. But maybe others with more knowledge of openocd internals could 
comment?
________________________________
From: Ooi, Cinly <[email protected]<mailto:[email protected]>>
Sent: Monday, July 19, 2021 2:34:06 AM
To: Tommy Murphy <[email protected]<mailto:[email protected]>>; 
OpenOCD 
<[email protected]<mailto:[email protected]>>
Subject: RE: Potential NULL byte injection


Hi Tommy

Me not being a hacker, I don't have a concrete idea on how to attack so the 
explanation here is somehow contrived and theoretical. I am just trying 
highlighting NULL byte injection is potentially possible. However, let me have 
a go.



Say a developer create these two commands in OpenOCD
 - "authenticate <user> <passwd>"

 - "run <cmd>"



to authenticate the user and to run any arbitrary command on the command line.

Unfortunately, "authenticate" is a naïve implementation that does "sudo su 
<user>" then supply the password. "run" then run <cmd> as that user



An attacker carefully craft an attack, tricking a user with sudo access to run 
a configuration file with the following line:

authenticate \x00victim PASSWORD

The victim did not notice the leading "\x00" in front of his username. However 
the attacker noted that, with this, <user> is now blank, and he is doing a 
"sudo su". Now, he can run any command as root user.



HTH

Cinly


The user obliged, unaware that the \x00 is translated to "\0" in C and thus,

From: Tommy Murphy <[email protected]<mailto:[email protected]>>
Sent: Saturday, July 17, 2021 6:00 AM
To: OpenOCD 
<[email protected]<mailto:[email protected]>>;
 Ooi, Cinly <[email protected]<mailto:[email protected]>>
Subject: Re:



Can you explain what exactly "bad" happens here that you are trying to protect 
against?

> # Attack Succeeded. It is equivalent to

> # jtag newtap arm soc \

> # -irlen 4 -expected-id 0x4ba00477

> jtag \

> newtap\x00attack \

> arm\x00attack \

> soc\x00attack -\

> irlen\x00attack 4\x00attack000 \

> -expected-id\x00attack 0x4ba00477\x00attack

________________________________

From: Ooi, Cinly <[email protected]<mailto:[email protected]>>
Sent: Friday, July 16, 2021 7:18:21 PM
To: OpenOCD 
<[email protected]<mailto:[email protected]>>
Subject:



Dear All

While doing security work on the aji_client driver we are developing for 
openocd, we see the following that looks like it is possible to do a "NULL byte 
injection" attack on openocd.  Having spoken to Antonio, he suggested that I 
post this to the mailing list. I want to gather opinion on what the community 
think about this finding.



To recap, "NULL byte injection" exploit the fact that the NULL byte is a 
termination character, so  human might be tricked into reading a string like

"passwd\00.png" as a PNG file, while in reality,  it is looking for the file 
passwd.



The config script below demonstrate the problem:

---

# use any driver at hand.

adapter driver aji_client;



# Attack stopped: invalid command name "jtag"

jtag\x00attack \

newtap \

arm soc \

-irlen  4  \

    -expected-id  0x4ba00477



# Attack Succeeded. It is equivalent to

#     jtag newtap arm soc \

#           -irlen  4  -expected-id  0x4ba00477

jtag \

newtap\x00attack \

arm\x00attack \

soc\x00attack -\

irlen\x00attack 4\x00attack000 \

-expected-id\x00attack 0x4ba00477\x00attack

---





My analysis says when we  that  openocd will manage to find out that we 
inserted a NULL byte for the first token of the statement, but not for all 
subsequent tokens.



The difference can be explained by the way the tokens in the statement is 
parsed:

(1) For the first token, parsing is done inside jimtcl/jim.c
https://github.com/msteveb/jimtcl/blob/master/jim.c#L4386

Here, it looks like jimtcl do a hashmap lookup to find a handler to interpret 
the token . The hashmap look up the command handler to interpret the token. 
However, as it uses the full token as key, e.g. "newtap\x00attack", it will not 
be able to match the hash of "newtap" and this negated the attack

(2) For all subsequent tokens, the command handler returned in (1) is used. We 
create the command handler. We have a tendency to use functions provided in 
src/helper/jim-nvp.c. In particular, we use

jim_getopt_string(*goi, *buffer ,* len)
for our tokenization needs. This function returns the full token, i.e. set 
buffer to  "newtap\x00attack" and len to 13. Most of the time, we then proceed 
to interpret the token as standard string using standard string operators, 
which means openocd reads the token up to the NULL byte. This mean the string 
that we used to is "newtap", not "newtap\x00attack". In other wordswe read a 
different string from what is presented and potentially allowed NULL byte 
attack to happen.





Subsequent work suggest that we can detect this easily,  by comparing len with 
strlen(buffer). With the same example, len=13 but strlen(buffer) = 6.



I tried a naïve method of fixing it, i.e. inserting this string length test 
into  jim_get_opt_string:
https://sourceforge.net/p/openocd/code/ci/master/tree/src/helper/jim-nvp.c#l208

to check string as below

int jim_getopt_string(struct jim_getopt_info *goi, const char **puthere, int 
*len)

{

                int r;

                Jim_Obj *o;

                const char *cp;



                r = jim_getopt_obj(goi, &o);

                if (r == JIM_OK) {

                                cp = Jim_GetString(o, len);



                             #### ADDED THIS IF

                             If(len != strlen(cp)) {

                                return JIM_ERR;

                            }



                                if (puthere) {

                                                *puthere = cp;

                                }

                }

                return r;

}


My new code introduced an extra return state, so it is not surprising that 
openocd failed. In fact it segfault-ed with this simple configuration file:

  adapter driver <yourchoice>

  jtag newtap\x00attack  newtap arm soc \

           -irlen  4  -expected-id  0x4ba00477


Best regards

Cinly


Reply via email to