Thanks for reply Dan,

I don't really know what I'm doing, but using your definitions

pwdcheck2 =: ('password' -: ]) NB. unlocked
PWDCHECK2 =: (<'pwdcheck2') <@]^:(1:`(<'@.')) 0

a =. memr (15!:14 <'PWDCHECK'), 0, 1, JINT 
b =. memr (15!:14 <'PWDCHECK2'), 0, 1, JINT 
memr   a,0,16,JINT 
56 0 184 262144 2 1 0 6443034000 6443033120 626935840960 0 0 0 
9223372036854775807 9223372036854775807 9223372036854775807 
memr   b,0,16,JINT 
56 0 184 262144 1 1 0 6443034000 6443033120 625002615568 0 0 0 
9223372036854775807 9223372036854775807 9223372036854775807 


They look very similar.  I think you are suggesting that the first could be 
unlocked by flipping one bit in here?

Though I don't see a single bit difference in an int there.

Does 9!:25 disable the 15!:n commands?

I guess even if it did, external processes can read memory.

Btw, the only secret I want to keep safe is the noun 'password' by embedding it 
in a locked verb that is set at run time, and while the verb is much more 
complicated, its template source is public, as is knowledge that the locked 
verb name is 'pwdcheck', and the byte size of the noun is guessable (though 
that can actually be obfuscated significantly).  I'm much more worried about 
external processes (virus/malware) than a process that could attach itself to 
the J session and query it (though I may be unaware of things I'm unaware of).  
Total process memory usage is not at all guessable, the timing for when the 
verb will be set is not predictable, and the overall program is large for J.

The planned structure of verb is more like this template that can be easily 
conjunctioned.

pwdcheck =: localvar&('password' [:`(dostuff@[)@.-: ])


----- Original Message -----
From: Dan Bron <[email protected]>
To: J Programming <[email protected]>
Cc: 
Sent: Monday, August 10, 2015 5:08 PM
Subject: Re: [Jprogramming] unlock.ijs

REB wrote:
>  No, Dan made a typo, he wrote /wsvn/ instead of /svn/ 

Blasphemy. Dan does not make mistakes ;)

In this case, I had used the recommended best practice of MoinMoin interwiki 
links: I never typed wsvn or svn at all; instead, what I had written was:

    [[JSvn:DanBron/trunk/general/unlock.ijs|unlock.ijs]]

The “JSvn:” interwiki shortcut is a layer of indirection which is supposed to 
protect Wiki editors from volatile URLs (while at the same time offering typing 
shortcuts which make linking more convenient).

However, in this case, the Interwiki repository has not been kept up to date.  
In http://www.jsoftware.com/jwiki/InterWiki 
<http://www.jsoftware.com/jwiki/InterWiki>, we see that JSvn is still mapped to 
http://www.jsoftware.com/wsvn/ <http://www.jsoftware.com/wsvn/>, though svn has 
been rebased to /svn/ (as you said) since. 

I’m not a MoinMoin administrator, so I can’t change the official Interwiki 
page, so I hard-coded the direct /svn/ link in the Unlock page.  I don’t have 
the time or will to go through other pages I control to make more systematic 
changes.  Better for Chris or some other MoinMoin admin to update all the 
/wsvn/ links on the central Interwiki page*. 

Pascal (originally) asked:
>  does the unlock script need access to the locked file, or 
>  does it do everything in memory?

It does everything in memory, but it relies on an exploit that (I believe) has 
since been patched. In short, this used to produce the definition of the quoted 
name, even when locked:

        'pwdcheck' f.
     pwdcheck

As you can see, as of J803 (at most), it no longer does.

The only other trick the unlock script exploited was 4!:5, used precisely as 
intended: to discover which names a script defines. That’s necessary because 
the “interesting” parts of a script may not be exposed in the documented 
interface.  

> Dan alluded that he could attack it in memory with undocumented 15!:6

The unlock script depended only on the (now patched) exploit  ‘name’ f.  . It 
didn’t make any use of 15!:6 .  

But you’re right that I made the claim:

>  I want to stress that the exploit above isn't the problem, only an 
>  demonstration of it. Even if Roger "fixed" f. and 4!:5, other
>  approaches are possible. For example, I could use 15!:6 and 15!:7. 

So, now that the very situation I described has occurred (i.e. Roger fixed f.), 
can I carry out my threat?

Well … not with a simple application of 15!:6 **.  However unintentional, that 
foreign can no longer be applied to pro-verbs, pro-adverbs, or pro-conjunctions 
[1]. It can only be used to get the address of pro-nouns these days.  Which has 
frustrated me on more than one occasion (see a list of personal utilities this 
change broke in the postscript to [2]).

However, while the easy paths have been closed, the point still remains: 3!:6 
doesn’t encrypt files, it merely encodes them.  As I said in the original 
message (and Wiki page), and others have pointed out in this very thread, it is 
not possible keep secrets from a user when the user himself holds the key.  

If you’re not entering a key, personally, every time a name is unlocked, 
someone else is. In this case, that someone is your user (via J).

With all that said, Raul and the others are right: security is a matter of 
degree, not binary, and J itself is a kind of encoding layer which will 
dissuade all but the most persistent of snoopers. Add a bit of 3!:6 encoding on 
top, and I’d call that “secure enough” for non-critical secrets.

-Dan

[1] J602 introduces breaking change to undocumented foreign 15!:6 :
    http://www.jsoftware.com/pipermail/general/2008-November/032554.html 
<http://www.jsoftware.com/pipermail/general/2008-November/032554.html>

[2] List of personal utilities the change to 15!:6 broke for me 
    (see postscript of this message):
    http://www.jsoftware.com/pipermail/programming/2013-October/033760.html 
<http://www.jsoftware.com/pipermail/programming/2013-October/033760.html>

* Upon investigation, it appears that /wsvn/ is also a valid URL, but only for 
web-browsing, i.e. prettified, for a subset of repositories hosted at /svn/.

** Argh, ok.  I don’t like to make assertions I can’t back up; I don’t want to 
develop a reputation for making empty threats.  So…

Earlier, Roger had said he didn’t know what had changed in J602 that made it 
stop working for proverbs etc [3], so I had a little look in the source.  
Here’s what I found:

    x.c (foreign definitions), line 201:
    
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/x.c#L201
 
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/x.c#L201>

      case XC(15,6):  R SDERIV(CIBEAM,jtdllsymget,0,RMAX,0,0);

    s.c (symbol table), line 222:
    
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L222
 
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L222>

      F1(jtdllsymget){R dllsymaddr(w,0);}

    and line 207:
    
https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L207
 
<https://github.com/openj/core/blob/18fd23bbdc2f50770eb3047e978cd5e4e3b47039/s.c#L207>

      static A jtdllsymaddr(J jt,A w,C flag){A*wv,x,y,z;I i,n,wd,*zv;L*v;
       RZ(w);
       n=AN(w); wv=AAV(w); wd=(I)w*ARELATIVE(w);
       ASSERT(!n||BOX&AT(w),EVDOMAIN);
       GA(z,INT,n,AR(w),AS(w)); zv=AV(z); 
       for(i=0;i<n;++i){
        x=WVR(i); v=syrd(nfs(AN(x),CAV(x)),0L); 
        ASSERT(v,EVVALUE);
        y=v->val;
        ASSERT(NOUN&AT(y),EVDOMAIN);              
        zv[i]=flag?(I)AV(y):(I)v;
       }
       R z;
      }    /* 15!:6 (0=flag) or 15!:14 (1=flag) */

So the culprit here is line 216:

        ASSERT(NOUN&AT(y),EVDOMAIN);              

That is, J has the answer I want in-hand already — it just refuses to give it 
to me. (To interpret this line, one must understand that there’s only one 
single data structure in the J engine, which is used to represent nouns, verbs, 
adverbs, conjunctions, and even some other stuff.  The NOUN&(AT) part says 
“throw an error unless this data structure is representing a noun".)

Now, since 15!:6 was originally introduced for the purposes of passing J data 
to other processes, it makes sense, and is a reasonable safety check, to 
restrict its use to nouns. But I have other uses for this function, which are 
hampered by this restriction.

So what can we do about it? J will refuse to return the address of any name 
which is not a noun. But we want the address of a verb.  Somehow we need to 
pass 15!:6 a verb, but have J believe it’s a noun.

Our mind first wanders to things like PWDCHECK=:’pwdcheck’, but then we realize 
nothing along those lines will work (the string ‘pwdcheck’ is just 
coincidentally spelled the same as the name of a function, but 15!:6 won’t be 
able to make that connection; it will just return the address of the literal 
noun ‘pwdcheck’ - wherever those 8 characters are stored in memory).

Then we remember the “disaster which smells like a breakthrough”, as Tracy so 
eloquently put it on Twitter [4]. Let’s use Marshall’s discovery [5] that that 
“breakthrough” permits us to box verbs:

        PWDCHECK =: (<'pwdcheck') <@]^:(1:`(<'@.')) 0

        PWDCHECK
     +--------+
     |pwdcheck|
     +--------+

        type'PWDCHECK'
     +----+
     |noun|
     +----+

        PWDCHECKOPENED=:>pwdcheck

        type'PWDCHECKOPENED'
     +----+
     |verb|
     +----+

        (>PWDCHECK) 'password'
     1
        (>PWDCHECK) 'not the password'
     0

Ok, here we have it. A verb cloaked as a noun, so that it can pass the test 
ASSERT(NOUN&AT(y),EVDOMAIN) .  Let’s try it:

        15!:6 <'PWDCHECK'
     140618867255944

No domain error. Great. But now we have to remember that 140618867255944 is the 
address of the box which contains the verb pwdcheck, not the verb pwdcheck 
itself.  What we need is the value of the first element of the boxed array, 
which, going off the comment on the final line of the function jtdllsymaddr(), 
looks like we can get using the (also undocumented) foreign 15!:14 (the macro 
AV(x) returns the address of the “ravel”, or value, of the struct x):

              15!:14 <'PWDCHECK'
           140618884704072

But this being a box, that address itself probably contains a pointer to the 
header of the function pwdcheck:

              memr (15!:14 <'PWDCHECK'), 0, 1, JINT
           140618882427152

Which looks like a reasonable address, not far from the block which contains 
PWDCHECK itself (which makes sense).

Indeed, if we use 15!:7 to set a new symbol pointing to this address:

              ‘someothername' =:15!:7 {. memr (15!:14 <'PWDCHECK'), 0, 1, JINT
              someothername
           pwdcheck

So we’re on the right track, for sure.  But of course we’re not home yet - 
we’re pointing ‘someothername’ right back to the _name_ ‘pwdcheck’, which 
doesn’t get us anywhere.

The next step would be to chase pointers to the value underlying ‘pwdcheck’ and 
manipulate the “flags” field to turn off the VLOCK flag (bit #16), as in:

              (memw~ (26 b. VLOCK=:65536) 17 b. memr) CORRECT_POINTER, 8,1,JINT 

Unfortunately, I’ve run out of time for pointer-chasing today. Nevertheless, in 
my mind the rest of this is mere stamp-collecting: we have the beginning of the 
thread, now we only need to pull it carefully to unravel the whole sweater.

[3] Roger on the change to 15!:6:
    http://www.jsoftware.com/pipermail/programming/2010-January/017946.html 
<http://www.jsoftware.com/pipermail/programming/2010-January/017946.html>

[4] Tracy on twitter:
    https://twitter.com/kaleidic/status/296101561459953664 
<https://twitter.com/kaleidic/status/296101561459953664>

[5] Marshall discovers that the stupid ^:(<‘@.’) trick allows us to box verbs:
    http://www.jsoftware.com/pipermail/programming/2013-January/031260.html 
<http://www.jsoftware.com/pipermail/programming/2013-January/031260.html>



----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to