4 ms·
Will this show a warning? for (int i=0;i<LEN; i++) { for (char c=0; c<255;c++) { if (tainted[i] == c) { untainted[i] = c; }
by ajuc 11y ago
Will this show a warning?
for (int i=0;i<LEN; i++) {
for (char c=0; c<255;c++) {
if (tainted[i] == c) {
untainted[i] = c;
}
}
}
send(untainted);
If no - protection doesn't work obviously. If yes - almost all variables are tainted (you don't usually read stuff that doesn't influence codepaths or global state in your application).
In the promiscuous world of imperative programming there's millions of ways to introduce dependency that can't be automaticaly checked.
For more complex - you can have workers/threads doing while() { sleep(), next_letter; } and other workers killing them after calculated time.
Or you can get different number of pseudorandom numbers from generator with known seed in one loop depending on tainted data, and after the loop untainted data is set depending on the current random number from the same generator. Calling rand() taints the generator.
I thought they would just mark the whole etension as tainted once it reads tainted data. And then any communication with other sites show the warning.
- moe 11y agoWill this show a warning? Yes, because the assignment happens inside a conditional that references a tainted variable. In the promiscuous world of imperative programming there's millions of ways to introduce dependency that can't be automaticaly checked. That is not true. workers/threads doing while() { sleep(), next_letter; } What is that supposed to achieve? known seed in one loop depending on tainted data Every variable assigned to within a "loop depending on tainted data" becomes tainted. Calling rand() doesn't taint the generator. Seeding it within a tainted scope does. Edit: I was wrong (see below), of course rand() also taints the generator.
- ajuc 11y ago> Yes, because the assignment happens inside a conditional that references a tainted variable. What if it was if (!tainted[i]==c) { continue; } untainted[i]=c; ? If your checker is smart enough to catch this - your whole program is tainted by your password once you check it in the login screen. > What is that supposed to achieve? Global state is incramented by another worker every second to the next value. My thread kills the other worker after N seconds. global state = N and I haven't touched it. If you don't want to call kill from if depending on tainted data - sleep in that if, and call kill immediately after it. > Calling rand() doesn't taint the generator. Seeding it within a tainted scope does. It does: set_seed(1337); for(int i=0; i<tainted[0]; i++) { rand(); } int tmp = rand()); // now I know what tainted[i] was // because I know how many times // rand() was called, because I know // the whole sequence because I know // (untainted) seed.
- moe 11y agoWhat if it was To clarify, tainting "scope" doesn't refer to variable scope but is commonly implemented as a (thread-local) global dict that tracks tainted access in execution order. In your example the variable 'c' would be tainted from the moment the conditional evaluates until it is either re-assigned (from a non-tainted source) or until the program ends. If your checker is smart enough to catch this - your whole program is tainted by your password once you check it in the login screen. Not sure what you mean by "your password" in this context. Which password, from what source? Calling rand() taints the generator Pardon, you are of course right. Yes it does.
- TheLoneWolfling 11y ago> What is that supposed to achieve? Timing attack against yourself. Something along the lines of the following, for instance: <thread 1> for (int i = 0; i < LEN; i++) { for (int j = 0; j < sizeof(char); j++) { while (flagA) {} if (tainted[i] && (1 << j) == 0) sleep(1); flagA = true; } } <thread 2> flagA = false; for (int i = 0; i < LEN; i++) { for (int j = 0; j < sizeof(char); j++) { sleep(0.5); if (flagA) untainted[i] ||= (1 << j); while (!flagA) {} flagA = false; } } (Note that it doesn't need to explicitly call sleep. It can do pretty much anything that takes an ~constant amount of time.) (Note that you can also leak LEN at the start, as to avoid tainting the loop.)
- moe 11y agoYour concern is valid but AFAIK web workers are shared nothing (please correct me if that changed). I think tainting can only be made reliable in a single-threaded environment.
- ajuc 11y agoThere are shared workers but it's not standard yet (I think). https://html.spec.whatwg.org/multipage/workers.html#shared-workers-introduction https://html.spec.whatwg.org/multipage/workers.html#shared-w... Even without shared workers timing attack works - untainted worker can connect to attacker site every second and update value, and be killed by untainted code after the tainted worker finished. EDIT: or you can do this with no multithreading at all, just getMiliseconds() before and after tainted code, and make the tainted part last secret_number miliseconds. Or if you blacklist getMiliseconds as tainting - do this on server instead. callAttackersServer(); { var tainted_int = getFromOtherServer(); for (var i=0; i<tainted_int; i++) { sleep(100 ms); } } callAttackersServer(); and the difference in time between calls will be interpreted on the server as the secret number.
- moe 11y agoYeah, timing attacks are indeed tricky. Within the call-stack we should probably simply consider all I/O that happens after a tainted variable was accessed to be tainted as well. That and banning trusted extensions from using concurrency mechanisms should sort those out. Correct me if I'm missing something, though!
- deian 11y agoRather than reply individually to the messages from this thread, I'm going to try to clarify some things here. I think a lot of good points were brought up both with regards to the "taint" mechanism and timing covert channels. IFC/tainting mechanism: The style of IFC we are proposing is not not the tainting style used by more typical language-level systems. In particular, we're proposing a mostly-coarse grained system: - A single label is associated with a context. A context can be the main extension context or, more likely, a light-weight worker the main extension context created. This single label is conceptually the label on everything in scope. As such, when performing some I/O this label is used by the IFC mechanism to check if the code is allowed to perform the read/write. This coarse-grained approach alleviates the need to keep track of tricky leaks due to control flow: the branch condition has the label of the context so any control flow within the context is safe. If you want to perform a public computation after a secret computation, you need to structure your program into multiple contexts (e.g. create a new worker wherein you intend to perform the secret computation). - Labels can also be associated with values. A new constructor Labeled is provided for this task. You can think of it as a boxing the value and, by default, only allowing you to inspect the label of the value. You can pass such labeled values around as you see fit (and this is pretty useful in real applications). Importantly, however, when you read the underlying (protected) value the IFC system taints your context---i.e., it raises the context label to let you read the value, but also restricts your code from writing to arbitrary end-points since doing so may leak something about the newly-read value. An important requirement of this IFC approach is that there be no unlabeled (implicit) shared state between the different contexts. For example, rand() in context A and B must not share an underlying generator. This kind of isolation can be achieved in practice and is an important detail when considering covert channels. Timing channels: It turns out that if you do IFC in this coarse-grained fashion you can prevent leaks due to timing covert channels, if you are willing/able to schedule contexts using a "secure scheduler." In [1] we showed how to eliminate timing attacks of the style described in this thread (internal timing channels) that are inherent to the more typical IFC systems. In [2] we extended the system to deal with timing attacks due to the CPU cache by using an instruction-based scheduler (IBS). IBS and other techniques to deal with timing channels are nicely described in [3]. (I'd be happy to expand here, but this is already a long reply.) [1] http://www.scs.stanford.edu/~deian/pubs/stefan:2012:addressing.pdf http://www.scs.stanford.edu/~deian/pubs/stefan:2012:addressi... [2] http://www.scs.stanford.edu/~deian/pubs/stefan:2013:eliminating.pdf http://www.scs.stanford.edu/~deian/pubs/stefan:2013:eliminat... [3] https://ssrg.nicta.com.au/projects/TS/timingchannels.pml https://ssrg.nicta.com.au/projects/TS/timingchannels.pml