Problem with closures, nCcalls on Lua 5.4.0 (alpha)

classic Classic list List threaded Threaded
30 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

David Heiko Kolf-2
Sean Conner wrote:
>   I thought that was clear from the context (this mailing list being about
> Lua, and the topic of getting address information from Lua leading to OMG
> Armageddon! but I probably should have been more explicit about it).

[...]

>   But so far, all I've seen is "OMG! ASLR is VIOLATED!  Burn the feature!"
> which to me comes across as cargo cult security, of which I seem to be in
> the minority.  So let's neuter both tostring() and string.format() to save
> ASLR!
>
>   -spc (And request, nay!  Demand!  That all modules in C avoid printing an
> address as part of the __tostring() metamethod ...)

I really don't like the mockery that sometimes pops up when security is
mentioned.

Yes, giving an address on its own does no harm.

Yes, well written code must never allow write or read access to
out-of-bounds memory, on the stack or on the heap, no matter whether it
is the Lua library or any external C bindings for Lua.

Is everybody writing bindings for Lua always writing perfect code? I
hope I do so most of the time, but I can't guarantee that I do it all
the time. And the list of published CVEs (in general, not limited to
Lua) seems to tell me I am not alone.

Is ASLR worth it or just some useless obfuscation we don't need to care
about? I can't judge.

If I would want to write a project that executes untrusted code, I guess
I would probably provide my own versions of string.format and tostring,
assuming I remember this issue.

Best regards,

David

Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Sean Conner
It was thus said that the Great David Heiko Kolf once stated:

> Sean Conner wrote:
> >   I thought that was clear from the context (this mailing list being about
> > Lua, and the topic of getting address information from Lua leading to OMG
> > Armageddon! but I probably should have been more explicit about it).
>
> [...]
>
> >   But so far, all I've seen is "OMG! ASLR is VIOLATED!  Burn the feature!"
> > which to me comes across as cargo cult security, of which I seem to be in
> > the minority.  So let's neuter both tostring() and string.format() to save
> > ASLR!
> >
> >   -spc (And request, nay!  Demand!  That all modules in C avoid printing an
> > address as part of the __tostring() metamethod ...)
>
> I really don't like the mockery that sometimes pops up when security is
> mentioned.

  And I don't like the "You must do this!  Think of the children!" rhetoric
that comes from the security domain. [1]

> Yes, giving an address on its own does no harm.
>
> Yes, well written code must never allow write or read access to
> out-of-bounds memory, on the stack or on the heap, no matter whether it
> is the Lua library or any external C bindings for Lua.
>
> Is everybody writing bindings for Lua always writing perfect code? I
> hope I do so most of the time, but I can't guarantee that I do it all
> the time. And the list of published CVEs (in general, not limited to
> Lua) seems to tell me I am not alone.

  Yeah, I looked up CVEs for Lua.  There aren't many, and what there are
aren't in Lua itself, but in other modules.  And NONE were related to
"knowing" an address.

  Also, if I am to believe some of the hype I've read about securly written
code, NOTHING should be written in C.  Ever. [2]

  So until there is a proof-of-concept of an exploit in Lua because of
tostring() printing addresses, I'm going to oppose any changes.  Think,
people!

  -spc (I'll stop now before I get truely cynical about things)

[1] Years ago I used to work in web hosting and I've been on the
        business end of PCI compliance.  There's nothing like a 500 page
        report of repeated issues where the fact that we have DNS, and you
        can ping (PING!  OH MY GOD OUR COMPUTERS ARE ON THE INTERNET!) our
        servers, and so on, ad naseum, for 500 pages.  Never mind the fact
        that we were a WEB HOSTING COMPANY!  It's like they thought we
        didn't even know networks existed!  I found it insulting and an
        utter waste of time.

        And frankly, it hasn't gotten better in my opinion, and leads to
        such stupidities as DNS over HTTPS because ENCRYPT ALL THE THINGS!
        without thought.  Just do it.  No, do it.  I fully expect in twenty
        years time that *everything* will be tunneled through TCP port 443
        because we can't imagine otherwise.

        Damn it we can't be paranoid enough, can we?

        Yes, I'm bitter.

[2] I toned down the language here.

Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Sean Conner
In reply to this post by Coda Highland
It was thus said that the Great Coda Highland once stated:
>
> (Also, where do you draw the line between "cargo cult" and "best
> practices"? Because I've certainly seen you describing the "right" way to
> do things before.)

  Bob's TV wasn't working properly and the picture would roll around (okay,
so this is an old TV we're talking about here).  He would whack it on the
side, and still, the picture would keep rolling.

  Bob got annoyed enough to take to the local TV repair shop.  He described
the issue to Alice, and sure enough, when she plugged it in and turned it
on, the picture would roll.  Alice then gave it a whack, and immedately, the
picture was stable.

  "What?"  asked Bob.  "I whack it, nothing happens!  You whack it, it's
fixed!  What the?"

  "Easy," said Alice.  "When I whack it, I *know* why I'm doing it."

  -spc (Like to think I can at least rationalize why I do what I do)


Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Roberto Ierusalimschy
In reply to this post by David Heiko Kolf-2
> Is ASLR worth it or just some useless obfuscation we don't need to care
> about? I can't judge.

I may be completely wrong here, but as far as I know the main motivation
for ASLR were attacks like stack overflow in C. As far as I know, in
C it is trivial (actually a non-op) to take the address of anything:
functions, data structures, the stack, etc. So, if taking addresses were
really that big problem, ASLR would be dead before starting.

The whole idea of ASLR was to avoid knowing addresses *before* being
able to execute code in the machine. Once you can execute code, things
get pretty hard.

For instance, I could agree with a complain that an error message is
showing a memory address. That is something someone can provoke
and see from outside, without running its own code in the machine.

Attack-resistant sand boxes are hard and tricky (even with hardward
support!). The string library is particularly problematic, because
they provide the only functions that can be called even in an empty
environment, and these functions can greatly ease a DoD attack.  (DoD
attacks in pure Lua can be stopped by debug hooks, but slow C functions
do not go through hooks.)  Should we remove string methods too, in favor
of "better security"?

-- Roberto


Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

David Heiko Kolf-2
Roberto Ierusalimschy wrote:

>> Is ASLR worth it or just some useless obfuscation we don't need to care
>> about? I can't judge.
>
> I may be completely wrong here, but as far as I know the main motivation
> for ASLR were attacks like stack overflow in C. As far as I know, in
> C it is trivial (actually a non-op) to take the address of anything:
> functions, data structures, the stack, etc. So, if taking addresses were
> really that big problem, ASLR would be dead before starting.
>
> The whole idea of ASLR was to avoid knowing addresses *before* being
> able to execute code in the machine. Once you can execute code, things
> get pretty hard.
>
> For instance, I could agree with a complain that an error message is
> showing a memory address. That is something someone can provoke
> and see from outside, without running its own code in the machine.

To be honest, I don't know of any application where Lua gets executed
like JavaScript in a web browser. So yes, this might be completely academic.

But I assume now there is an application that opens documents and
executes Lua scripts in those documents, expecting that everything is in
a nice sandbox. In this sandbox there is access to a broken userdata.
The userdata has a setvalue function that writes an integer to an array.
Whoever wrote it, missed a bounds check.

Now I am not a security expert. But as far as I understand, without
knowing where the userdata is and where some executable code might be,
an attacker could place code on some random memory position and hope
that it replaced a soon-to-be-called function -- more by chance and
probably the application would rather crash.

But with the address known, the following is possible:

  -- 'weakuserdata' provides access to a 32-bit integer array where
someone forgot bound checking

  targetaddress = tonumber(("%p"):format(print):sub(3), 16)
  openingaddress = tonumber(("%p"):format(weakuserdata):sub(3), 16)
  d = (targetaddress - openingaddress) // 4
  -- The following hex numbers are supposed to resemble machine code
  weakuserdata:setvalue(d + 0, 0xabcdef01)
  weakuserdata:setvalue(d + 1, 0x23456789)
  weakuserdata:setvalue(d + 2, 0xabcdef01)
  -- ...
  print() -- execute our own machine code

But again, I do not know of an application that executes Lua in
documents. And yes, some other bug would already need to exist. But
still I am thankful for those who point out that we need to be careful
around certain functions.

> Attack-resistant sand boxes are hard and tricky (even with hardward
> support!). The string library is particularly problematic, because
> they provide the only functions that can be called even in an empty
> environment, and these functions can greatly ease a DoD attack.  (DoD
> attacks in pure Lua can be stopped by debug hooks, but slow C functions
> do not go through hooks.)  Should we remove string methods too, in favor
> of "better security"?

Of course not, but the functions string.rep and the pattern matching
functions are already known and I would replace them with a
resource-limited edition if I were ever to write software where a Lua
code DoS might be an issue.

Same with the pointer issue, it is quite convenient and I actually
wished myself in the past that I had some kind of "rawtostring". But I
do find it helpful when people mention that there is a trade-off that
especially those who would write sandboxes need to know.

Best regards,

David

Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Coda Highland
In reply to this post by Roberto Ierusalimschy


On Sun, Jul 7, 2019 at 9:12 AM Roberto Ierusalimschy <[hidden email]> wrote:
> Is ASLR worth it or just some useless obfuscation we don't need to care
> about? I can't judge.

I may be completely wrong here, but as far as I know the main motivation
for ASLR were attacks like stack overflow in C. As far as I know, in
C it is trivial (actually a non-op) to take the address of anything:
functions, data structures, the stack, etc. So, if taking addresses were
really that big problem, ASLR would be dead before starting.

This isn't necessarily true.

I mean, if you're compiling and executing arbitrary untrusted C code, you're already doing something wrong to begin with. But disregarding that, even C code shouldn't be able to arbitrarily snoop on the memory space of OTHER processes. In a secure system, you wouldn't want a C program to be able to -- for example -- leak data from kernel structures, or probe the memory layout of a running service. Before ASLR, it was fairly simple to figure out a system's memory map after a clean, deterministic startup. ASLR means that even if you were able to get unauthorized privilege escalation in C code you still have more work to do before you can go start messing around in the kernel.

As I said, it's about defense in depth. Pointers are not themselves evil. Pointers to things that don't belong to you, on the other hand, are a foot in the door.
 
The whole idea of ASLR was to avoid knowing addresses *before* being
able to execute code in the machine. Once you can execute code, things
get pretty hard.

For instance, I could agree with a complain that an error message is
showing a memory address. That is something someone can provoke
and see from outside, without running its own code in the machine.

Attack-resistant sand boxes are hard and tricky (even with hardward
support!). The string library is particularly problematic, because
they provide the only functions that can be called even in an empty
environment, and these functions can greatly ease a DoD attack.  (DoD
attacks in pure Lua can be stopped by debug hooks, but slow C functions
do not go through hooks.)  Should we remove string methods too, in favor
of "better security"?

Of course not. Lua shouldn't be expected to remove a core piece of functionality just because of a security risk. That simply wouldn't make sense.

All anyone is seriously asking for is to provide engineers with the tools to create a secure environment when it's needed. I'm not going to presume to dictate the specific choices that should be made here; as I said before, this is outside of my use case and I'm only trying to prove information. I understand who cares about it, and I understand what the impact is from a security perspective, but there are various ways to handle it and I would rather leave the details to the people who know the system best.

/s/ Adam
Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Sean Conner
It was thus said that the Great Coda Highland once stated:

> On Sun, Jul 7, 2019 at 9:12 AM Roberto Ierusalimschy <[hidden email]>
> wrote:
>
> > > Is ASLR worth it or just some useless obfuscation we don't need to care
> > > about? I can't judge.
> >
> > I may be completely wrong here, but as far as I know the main motivation
> > for ASLR were attacks like stack overflow in C. As far as I know, in
> > C it is trivial (actually a non-op) to take the address of anything:
> > functions, data structures, the stack, etc. So, if taking addresses were
> > really that big problem, ASLR would be dead before starting.
>
> This isn't necessarily true.
>
> I mean, if you're compiling and executing arbitrary untrusted C code,
> you're already doing something wrong to begin with.

  Technically speaking (the best kind of correct 8-) we do this *all* the
time.  Did you audit the code for Firefox?  Or Chrome?  No, you probably
downloaded the program from the official location and ran it with little
thought, under the assumption that the code won't do anything nefarious to
your computer or data.

  And even *if* you download the code to a program, it's statistically
unlikely anyone here audited the code.  Sure, it *can* be done, but the
Heartbleed exploit in OpenSSL pretty much showed that isn't necessarily the
case for even a critical, security-based piece of software the entire
Internet uses.

> But disregarding that,
> even C code shouldn't be able to arbitrarily snoop on the memory space of
> OTHER processes. In a secure system, you wouldn't want a C program to be
> able to -- for example -- leak data from kernel structures, or probe the
> memory layout of a running service.

  But programs *can* do that.  Yes, there are typically restrictions (under
Unix for instance, only programs running under the same UID, or a UID of 0,
can do this).  Otherwise, it would be impossible to use a debugger (a
program who's sole existance is to probe the memory layout of a running
process).

> Before ASLR, it was fairly simple to
> figure out a system's memory map after a clean, deterministic startup. ASLR
> means that even if you were able to get unauthorized privilege escalation
> in C code you still have more work to do before you can go start messing
> around in the kernel.

  I get the feeling that most around here don't understand how this stuff
actually works.  Take the following C function:

        int stupid_auth(char const *name)
        {
          char buffer[40];
         
          puts("Name?");
          gets(buffer); /* !!!!! NEVER USE THIS FUNCTION!!!! */
          if (strcmp(name,buffer) == 0)
            return 1;
          else
            return 0;
        }
       
  It's the call to gets() that is problematic, since there is no way for it
to check the length of the character array it's given and this is a buffer
overwrite waiting to happen.

  In the old, pre-pre-ASLR days, programs were bound to fixed memory
addresses *and the stack was marked as executable* [1]. The stack layout is
known (still is, post-ASLR) and at a known address.  Assuming a 32-bit
machine, the stack would typically look like:

        +-----------------------------------------------+
        | address of "name" parameter (4 bytes) |
        +-----------------------------------------------+
        | return address (4 bytes) |
        +-----------------------------------------------+
        | previous stack frame pointer (4 bytes) | <- stack frame pointer
        +-----------------------------------------------+
        | buffer (40 bytes) | <- Stack pointer
        +-----------------------------------------------+

  All an attacker had to do was feed 44 garbage bytes to get to the return
address, write a 4-byte address, overwriting the actual return address with
one pointing into the stack, then as many bytes as required that comprise
the code to run.  Classic buffer overrun.

  There's an easy fix---mark the stack as non-executable [2].  Of course
attackers got around *this* by using "return oriented programming" (ROP).
For that, the attacker identifies the addresses of useful sequences of
already compiled code, and instead of sending code to be executed, sends a
sequence of data and return addresses (basically constructing a custom
sequence of call stack frames) to do the work instead.

  The response to THAT was ASLR---randomizing the addresses used in a
program; not only the stack and heap, but of each function as well.  No
longer are there fixed addressses an attacker can rely upon.  That still
leaves the issue that addresses are fixed *relative* to each other.  You
might now know the address of function foo(), but it is always 1024 bytes in
front of function bar().

  "Aha!  See!  Knowing an address is *still* bad!"

  Well, yes and no.

  If you get the address of a function, like the Lua function file:read(),
that only tells you the locations of other functions *in Lua* and not
necessarily any other function in the program.  In ASLR, not only the main
executable at a random location each time, but each shared library gets a
new address as well, so knowing that file:read() will only get you other Lua
functions that come with Lua.  It won't help you get the address of
(luafilesystem) lfs.rmdir() as its in a different library, loaded at some
random address.  And Lua is not a large library, so the availability of
useful code for ROP is limited (on my system, that's only 124,336 bytes of
code, of which a good portion is NOPs [3] for function alignment to keep the
speed up.  And while that sounds like a lot, it's not (Apache, the web
server I run, is significantly larger), especially when you consider the the
C runtime has over 1,000,000 bytes of code (again, on my system---the size
on your system may vary) to find useful fragments for ROP.

  So, to exploit the fact that you got an address:

        1) if it's an address of data on the heap, it does you no good for
           an exploit because you can't do ROP
        2) if it's an address on the stack, it does you no good because you
           still need the address of functions for ROP
        3) if it's an address of a function, that only gives you functions
           in that library (or main code), which limits how well ROP works,
           and it *still* needs an address to the stack to even begin
        4) you still need to find a way to overflow the stack

  This is why I consider seeing an address printed is a non-issue.

> As I said, it's about defense in depth. Pointers are not themselves evil.
> Pointers to things that don't belong to you, on the other hand, are a foot
> in the door.

  You can do all this and *still* be exploited:

        http://boston.conman.org/2004/09/19.1

  Okay, that was an inside attack, which is *very* hard to defend against.
And I'm not saying *don't* bother with security at all.  I'm just tired of
the knee-jerk reaction of "let's do this because security!" leaving people
with the illusion of security when they aren't.  Understand the threat
model.  Just because you have ASLR and don't print addresses doesn't make
you safe from exploits.

  -spc (WON'T YOU THINK OF THE CHILDREN?)

[1] Why in the holy hell would any operating system do this?  Because
        it's useful, that's why.  Microsoft Windows famiously did this for
        the BlitCopy routine, compiling code on the stack specialized for
        the type of operation required, and yes, even with the overhead of
        "compiling" it was *still* faster than a generalized routine.  It's
        talked about in the book _Beautiful Code_.

[2] It might make the system slower as techniques in [1] can no longer
        be deployed as easily.

[3] No OPeration.

Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Roberto Ierusalimschy
> [...]
> And I'm not saying *don't* bother with security at all.  I'm just tired of
> the knee-jerk reaction of "let's do this because security!" leaving people
> with the illusion of security when they aren't.  Understand the threat
> model.  Just because you have ASLR and don't print addresses doesn't make
> you safe from exploits.

+1. Thanks! :-)

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Sean Conner
It was thus said that the Great Roberto Ierusalimschy once stated:
> > [...]
> > And I'm not saying *don't* bother with security at all.  I'm just tired of
> > the knee-jerk reaction of "let's do this because security!" leaving people
> > with the illusion of security when they aren't.  Understand the threat
> > model.  Just because you have ASLR and don't print addresses doesn't make
> > you safe from exploits.
>
> +1. Thanks! :-)

  And an amusing bit of security knee-jerk reactions from another mailing
list I'm on:

> I heard from one user whose ISP is blocking incoming port 80 (everything
> can be reasoned with "security" nowadays).

  -spc (BLOCK ALL THE PORTS!)



Reply | Threaded
Open this post in threaded view
|

Re: tostring userdata

Luiz Henrique de Figueiredo
> > I heard from one user whose ISP is blocking incoming port 80 (everything
> > can be reasoned with "security" nowadays).

This is no joke. Entire sites are blocked from Brazil. When I visit
https://www.rogers.com I get

Access Denied
You don't have permission to access "http://www.rogers.com/" on this server.
Reference #18.1698c0ba.1562691192.c09a664

12