uuum ok uuuhhhm This is not really a new topic as far as RE Dos goes it’s just an old attack… The thing I’m bringing to this that’s sort of new, is automation, so, um, and some benchmarking, too. But what I mean by automation, is with NFA engines, you have to uuhm to kill the performance, you have to craft an evil stream and um, normally that takes a little bit of craftiness; you have to underrated that expression a little bit and know what would make it perform terribly. That’s the part I automated, and I have a tool that I released, and there will be a demo at the end for that. So that’s to know what to expect. Um, but I will go through regular expressions, how the DOSing works and all of that first. Um, but before I start with that, I just wanna give some shouts and some credits to some of the places I hacked at, and did my security research at, cuz that’s where I did most of it. So, HeatSink Labs from Phoenix, when I used to live there and then my new life in Manhattan so aaaah NYC were just trying to start hacking manhattan, is where I did a lot of the later stuff. So I'll going to depth in this slide. but about me, I'm Eric, im not a security researcher, there is my E mail address, my blog is there, that has more details about the other stuff. not some reg x But some like low level assembly machine code stuff i talk about. I'm always talking about how assembly language is too high level, and in my github and at the bottom its smaller just to fit the screen is the specific pearl script that is the tool that I will be talking about later in Demoing. and when i saw im not a security researcher, its kinda funny story, I typically don include a company name or title or anything in my bio.so when you dont do that you can always notice people that says “security researcher” after the name But I mean I did not put that because I really don't know what security research is so I just play hack. So this first part come the first third of the presentation, im gonna make this part really quick coz there a lot of hand so, ill try to race through this but this is kind of a tldr of regular expression there is more to it but like this is 90% like you would ever use and for some one that never use regular expression,like even learning half of this stuff you can get moving really quickly and be useful. Like I said I'm really going to race this. like i said with all the heads that went up i didnt even expect that, and uuuhhm you know what im almost not even gonna try to explain bout regular expressions are, I mean is a great way to search is the way to look at it. it kind of a programming language, its Non training complete. which that being kinda Like a language is why you can have performing issues but is like you know when you are doing file searches you can do dot* *dot or a question mark or or one character or whatsoever, it kinda like that kind of a syntax but its way more powerful, so first of all well talk about pawn of fires, say I was looking in bio or any kind of data or pact or anything, if I wanted to 5 or anywhere between 5 to 15 exes like the syntax of that… of that search so X and the amount from 5-15 and then we have aliases for useful arranges that we use alot so If you wanted to say 0 to 1 of that like the letter X. That's just a question mark after the X or a plus is something like X plus will be 1 or more Xs. Now say 1 or more I want to say to infinity here. but thats not completely true, there is a limit. But then the star is not like a star when you are doing file searches. like the glob kinda format, It means 0 to infinity. So is kind of like 1 or more or also not all is there as well. So. There is also character classes. So you group a certain kind of character im looking of 3 5s and 9s in my stream, and I want to find 5 to 8 of those because of that a string like that can match. Also negative space you can select the character class. that is negated so this right here, this little carret is a negation, this is the class that were negating the coma, What this really this really mean is one or more is not a comma so the string down here is red is the one that matches one till we hit the comma. Somehow, wow. I have no idea how that just happened. So give me a second here man, technical issues. Whats up? Oh weird is doing that scale mode. Does anybody know LSX good enough to get out of the scale mode? Hey, Joe. No, no that worked. Cool. I'm back, back in track. so my alias is for character classes you can do wide space, numbers, alphanumeric also under score and then if you capitalize it thats negate character class, so not number, not wide space not alpha numeric, have you a dot which is kind of like the questions mark in blogging so thats any character except for new lines. Unless not because you can modify that too. So we can also do kind of like an org statement. so if were looking for any of these three words from the stream Like good, bad evil. This string down here nonevil sentence will match the part that matches the word evil, so it had one of those in it. We can also group it as well so if we did good, bad, evil and group it with parenthesis we can say 3 or more of that so any one of those words. we have bad good evil bad, so anyone of those three words we had 4 of them we had matches, we can also anchor so what that means is For the carret not in the carret plus but the carret means we want to find the word anchor in this case this is out regular expression, but uuuhm the string has to start with the word anchor. so a string that would match is anchor is an anchor, But the thing it doesn't start with that word it starting with the word boat is an anchor, it does have the word anchor but the is is it doesnt start with the word anchor it starts with word boat, and we can do the same thing with end anchor. The dollar sign so that's the regular expression and a string that will match as anchor because it ends anchor, this will not match because it starts with a boat and not anchor, if we want to search a string for a character that a regular special character so we have to keep it with backslash so if we are looking for 3 to 6 dollar signs we have to stay this is an escape a dollar sign on an end anchor. And this is like the last red x because this is like boring stuff if you already know reg x, and I’ll get into the dos. there is greediness laziness, and possessiveness. Is a useful thing to know. A source of confusing when things are not matching the things you want. but a good example it kind of an HTML, example here Because reg x is the best thing to part HTML (inaudible) I don't know if you have seen but in this case I have scrip tag not really and end the script and then we have a text and we start another strip and then we end that and then more text so if we have general expression trying to find the first strip tag and everything in between it. That will kind of work if we have only one strip tag. but because reg x by default is greedy, it tries to capture everything. The thing that it matches starting from this first script. Wow this whole presentation. Starting from the first script to the last script to the second to the end script tag. So if we want to just the first script here. We can use that question mark modifier after the quantifier which is the plus in this case. And it does and tells the next one we’re looking for. Not everything until the next one. So now ReDos so now its all evil because is red. I'm going to take a drink of my caffeine. So before we start attacking there is more than just these two engines but these are the most commonly type of regular express engines. There’s hybrids too. But there is a deterministic engine and a nondeterministic engine. they have different kind of problems when it comes to performance usually when you read up on ReDos and uhhm NFAs are the engines most talked about, and the way the Dos it is thru time, deterministic engines is a little bit different because timing wise, because timing is it doesn’t really even matter what stream its on searching it kinda deterministically, time wise find other different matches or not, but you don’t get that for free, the downside is that it takes up memory to build the state table, so if you gonna wanna Dos and expression you kinda wanna know what engines it is using coz your strategy is gonna be a little bit different, you can actually do a recon to find that out, because they don’t actually, it’d be nice if they work is actually the same, as far as the output that you get, but it doesn’t completely, like on engine, if you a had a risk of -— one of em will pick the first one and another engine will pick the longest one instead, and also the laziness the DFA doesn’t support, and possessiveness is handled really weirdly for one of engines, so we can test it with like a proof of concept perhaps i can show a different results and show what i mean when i say that, so the longest alternation thing, the nfa, which is the first example here and ill zoom in, the sample stream im echoing out the stream is A B and the search that im doing is A or AB and the match that we get is just A. So really what's happening is we are picking the first thing that we see that matches the string and the first thing we see is just the A and now we're done we don’t match it we don’t get anything more than that, Another hand the DFA we do AB it grabs the largest thing. It actually match it is AB the full AB. So there is a difference in what it matches. And laziness this example is pretty straight forward because DFA doesn't support it. So we have a search string of ABABA. We search for A and any amount of character until the next A which make sense to why we get ABA. But we use the DFA we are still trying to say the same thing, that laziness that question mark. And it doesn’t work and that’s why we get, ABABA. Because it is with A and anything amount of anything until another A is how is working. So it just keeps on going. B doesn’t amount of anything. A is in the amount of anything and B is now like that. This one is really weird. With NFA when they find something that matches as is going along. It holds onto it and it doesn't want to give it back and it keeps going. So in this case we have ABC as the search string for both. And out expression is a little bit more complicated but just to break it down. We are looking for an A and maybe a B and then we're look maybe a BC 0 or 1 BC and both of the expressions that's what we're looking for. So for one of them we get AB and another we get ABC. So is weird why we get that. We get AB for one and ABC but if we follow it with NFA we get RA and the next thing is we get our A and there is also going to be a B. As we find that so we hold onto that and now the last part of the string. We have a C and is not a BC so we match them with AB where as the DFA will see the A and then the B will match with BC and longer stream will match so it gives up the first part to match the longer string so that's handle a little different. And as long as recon goes thats the biggest assumption, that you to have the ability to know what the system expressions are to be able to know what is matching so sometimes can you not do that recall and another thing you can do is can give it a string and you know what the expression is you can time it and if it takes the same amount you are dealing with the DFA if it is inconsistent in the time if it is longer than others then is either a DFA or hybrid. So we'll do comparison between on the engines still on how them work on the backend. So I'll start with the lies to simplify things and we'll go under the hood as we go. So the first kind of simplify version on how it works [ inaudible ] on how an engine would do path finding and this is going to be the NFA example so kind of like go down just the follow one side of the maze and if it hits the dead end it backtracks and go take another path. So this is how it would look like. Backtracks that dead end. Comes out finds another backtracks that’s how it goes. Depending on the mace looks you don’t know how long it will take through depending on how the dead ends are. With DFA in parallel it will go through all the options and picks the one that will work. It deterministic how fast it goes. And then you get the longest match. The problem is you're doing all that at once and it takes more memory. So part 2, with say this is our example regular expression at the top kind of in the blue and at the bottom I am wondering yeah, contrast is not as terrible. Well at least on my monitor here. That’s kinnda stupid. So red is the search string. So with the NFA engine. It starts as -- it takes a look at the expression and see how is matching with the string. 0 or more L, no. A, it doesn’t satisfy the [ inaudible ], no, there you go, that matches. So then we go to the next part know that that L doesn't match because we are still looking for more L so the I, so we go to the next part of the expression, is that T? No is that a C? No. Is that an I, Yes. We can go to next part there and as a T, no. Is that a C, yes. Is than an A? yes. And we can qualify and keep going is that a T? keep going you know and then this is where a search fails. Is it a C, no. Is it a C, no. Some I, no and then we're done that's the match. So the difference, I’ll get into how the DFA does it later. But also you can flowchart that out into a state diagram, is kind of messy but this is natural state diagram will be for this specific example back here so we start at nothing and at the bottom here we go, is this an L? But it doesn't have to be. Then it’s kinda could go back. This is were we diverge our three Different patterns and our alternation’s list. what I meant by that is back, there we go. We have our T group, or CA group and our I group. So going back there we have like at the bottom there the T, right there we have our CA and then we have our I and then in green is like our we solve it state it matches state. And if you really wanted to pop the hood there is a way you can actually get pearl to tell you exactly how is compiling a regular expression. so again this is our expression on the top. And this is kind of the programming language side of it how is being compile. And I say at the begin I said that it is not training complete because you cannot have an infinite loop. To the best of my knowledge, but in theory you shouldn’t have an infinite loop. You can have an itteration that can goes over over and over. Backtracks and over but you shouldn’t have an infinite loop. So in other words it should finish. So the F in the DFA is a finite [ inaudible ]. And this is just moreover that same expression. So DFA is little different. This is like more of a lie of how it works. It really doesn’t work this way. Is more string base. It looks at the string and it says, does it match the expression? It follows the string more than the expression its itself. And this is what a DFA state would look like. It has multiple ways to match. And it picks the longest match. Whereas NFA would pick the first one. And it is done when it picks the fist one. And this is a more accurate way. If you running an engine a DFA engine in a programing language is like you are going to be sitting up in array and its like a state diagram you are going to go through the states is a lot easier to comprehend on how an NFA engine should work. so this is again, this state diagram is not arbitrate is following the same example like the application string like reg x. So if we start on state 0, up here. In state zero, does it have an LTCR or A. It eventually gets you that L and when you do that just tells you now you go to state that listed in the diagram which is 1 so now we'll be on state 1 and we'll look for any of those letters. And whatever letter that is. And it instructs you which state, 2, 3, or 4 if you had a C it will instruct you to go to state 3. And eventually you will get a character that is no there which would completely fail or you would match eventually. And that's important to look at DFA in that context because that gives you an idea how you can dust the memory. Being is a table in memory what ways can you make that table grow. One way is you can have more of those patterns you're looking for or you can have a lot more states and I learn that states are the easiest way to attack it, in practice. In theory it should work, but in practice having more states is the way to do it. Is now talking about abusing DFA, we'll talk about abusing NFAs after this which is more complicated. But thinking of the labyrinth this is how I could abuse it. You will give it multiple paths to expand that memory out. It has to traverse all of them at the same time. That’s what I would explain there. that's kind of an example, that’s a POC. An expression that not even getting to the point of giving a string to search just the fact that it has to load that expression as a state table that will consume that memory. that expression. Because to break it down in this first set of parentheses we are looking for to 0 to 75 A. And the group that and we’re looking for 0 to 75 of that and 4 times 0 to 75 of that so it multiplies pretty badly. Now we'll talk about abusing NFA. I'm going to check the time here, we're good. Going pretty fast. This is another labyrinth. One important thing there is no way to solve it. You see a start up here. But there is no solution. It tries to go every path it can to try to find the solution but if it doesn't it backtracks and tries another way and it backtracks and tries another way. So if you give it a way out once it got out it will be done. It be match. So you just make it try every single possible thing. At the end it doesn't even match but it but that takes a lot of time so thats the way to abuse NFA. so the way to kind of conclude that is to try everything until it finds a match, dot, dot, dot. So I don't know about the contrast here. They have a pretty easy to understand example on how that should work. You have an expression, that It has to start with A, one or more A’s and then grouping one or more of that and end anchor it and give it different character and make it fail and that's what they do. Their example, say you add 4 A as and an X. That will give it 16 possible paths that it would find out that it is not matching. but if you just gave it a little bit more As that example there, 65 thousands different paths it has to take. Which takes so much longer. But unfortunately that's the naive assumption that the reg x is not going to do a any or the engine will not going to do any of a little bit of optimizing. So like optimization without thinking I'm going the flood the word but is getting optimize to that right there. So kinda a metaphor for that for any hard core C people with compilers this optimization as well. Even if you don’t know C, this is really like child's play. This is saying the number we get if we're actually not taking it in but if 5 is greater than 0 print true otherwise print false. That's pretty simple. So when we actually compile it, with a debugger. Is not actually doing a lot we're just making a call here after we set up a stack frame. And you know we already have this true populated and registration there and if you are looking at the X to the program itself we have true but we don’t have false. But it’s true meaning is straight going to print app. Just printing true because the compiler knows that in this case back here there is never a situation for this code where false is ever be true. It already knows that. So why compile that, why even make code for that. So we have trick the optimization and only just a little bit, just simply. So we make a variable that's equals to five and we test if that variable is greater than 0. So that's all we have to do to make the compile not able to understand what is doing. So when we do that simple modification. If we look at that at the debugger. We see that is moving 5 into an area and it is comparing right there with the 0 and we do have some conditional instructions. Until we actually get into the call print out. So if you look at memory you see it has true or false state. That's what we have to do reg x. I know it’s like a tangent kind of analogy. But we kinda do that with similar expressions. So in the OS example they are doing a plus so what’s kinda similar to a plus so we kinda use the curly braces. The ranch thing so we can say, this is our range, is like almost one or more, right? So to kind of format that example in that way to replace all the pluses with one more than nine thousand. We have that group and we have 1 to 9 more than 1 thousand again and anchored. I would zoom out of this but this is me benchmarking it so I did not do AX I did AB with that expression there and I timed it use your bend time and that first one there we have almost a second and you'll notice I'm increasingly adding an A each time I test the time, right? So I go back to actual timing, one second, two seconds 4 seconds. Almost 10 seconds. 15 seconds. You see what's happening here after we add one more A each time. It doubles. And then we see these two down here. like .02 seconds. That really was the original OAS example. So you see it really getting optimized. It doesn't take a long time you still have to trick it. And you might be thinking. There’s not a lot of time to have control to the expression itself. Because this is considering you do have control and you do get to make bad expression, it does happen rarely. One kind of really naive but still it happened scenario is you a server side validation for someone trying to sign up for an account in a web site. On the client side you just Dos yourself. But server side when you are registering your user name and password it wants to make sure they're not the same. You should never use regular expressions to check that. But in case you did, For the username poor regular used expression and for that password you have a string that dos it. Dosing that in the server. It’s a run down to benchmark. I get more gnarly about that later down. Now we talk about the animation the theory of what goes into it and I'll show some cool funny examples of that and then I'll do a demo of the script that I wrote. DFA have not gone that much attention. As far as research. But is the easiest to benchmark. And that is all that you can do. You can only benchmark it. You can’t really like make something worst for the expression already. So its either its good or it is bad. So if are you dossing you just kinda be aware of what a bad expression is for typical like dos or D dos situation instead of like loading a web page you just do a post to that expression with the string that's arbitrary. It doesn't matter. Now you are making it low that state table and consume memory. so what I did to benchmark it I use the Re 2 module and I used perl. And I slowly starved it of its resources. So I would load the state table used the module again but I would tell it to use a little more memory and try again and a little more memory. Eventually I'm going to get some errors that it ran out of memory and I capture that and record it. And this is yeah, so that's all for DFA I'm right into NFA now. So for NFA it is more complicated. The string matter. So how do you automate that, how do you say look at expressions and know this one will not preform well when you don’t know what string is attach to it. you can't just give it an arbitrary string and timed that. You kinda have to some way automatically generate a string that is bad. And in my case, generate a string that’s good to. So not only I could compare like is this string generally bad for any strings. Or somebody it like an expression that it might be okay given the environemnt but somebody still can abuse it and I keep track of all that. And one way to think about crafting a really bad string is I call it long circuit attack because when you are thinking of programing languages in C you have a bunch of ors conditional like if A or B or C or D and on. If are you variable had A is not going to evaluate anything after that, if it has A it stops. So if you long circuit it. You have a string like, it has everything ABC and the last one is not. So it fails on that part. Another thing is if you see a quantifier. My string will pick up as many as possible. if is you know A plus I'm going to put a bunch of A, if you is A 1 through 15. I would pick 15 A’s. And for any alternation I pick the last alternative so it has to look at all of them so it gets to that. Here's an example. This is expression, either an AB or CD or YZ. Anywhere from 1 to 20 of them and then a G. So simple example that will match and this is what will match the quickest. AB satisfied. And that was one of them. And that happens to be a G we are done. We matched. An example of what will take a lot longer. There’s a YZ, you got to look at AB, no. CD no, YZ yes. Ok there’s a YZ. is the next one a G? No, okay, so is it AB, is it CD, is is a YZ. So we do that 20 times and then eventually A it will pick A because is not G. So it still has to look at everything and backtrack, everything and backtrack and that's the longest it will take to solve that one. Is and as far as the complication to automating this, say our expression end up with a G. which will start 0 or more, 0 is an option so being that I have negate that last one this YZ YZ YZ A will still match because I do not need to have the G at that point so I still works. I have to find a way to negate the last [ inaudible ] that isn’t optional. So anything star so any 0 to whatever number quantifiers I can’t use those or even the question mark one. So I made a script called bench wreckers IPL. I'll show you some example output of some arbitrary strings and then I'll show you it working but I thought it will be cool at some example to see what tricks it does for it. So the expression at the top is hi. That’s the regular expression. My script will output Ha like it match it is first part and negates the last part. So that’s how it works. So being we got ha from here. So let’s use HA as the expression and see what it does with that. I said HA and it says H 1. Still negates it. So I did 1 to 15 A and then an H and then a [ inaudible ]. Well you know again, the most amount of quantifier and that’s 15 A’s and then an H not an bang. A it still fails. But it makes [ inaudible ] possible. Again like a big long alternation of a lot of alternatives and then a D and a one, the last alterations it does a D but not a 1. I do any amount of Hs like where are one or more Hs and then an I then an H’s then an A. This one okay yes, so it has 7 X and then one or more or one to 10 As and that 1 to 10 times, but it picks up just the one. Because you cannot have any A’s. This one is more interesting is kind of the same thing but we are just adding an end anchor to the end of that. So it starts with the X. It does a whole bunch of A so it can end with a 1 so it has to do a lot of backtracking to see the most time to evaluate so it know it doesn’t match. so this is the script I was talking about. What you do is use a text file with a lot of expressions. It goes through them all it does a memory testing. It generates the good needle string and test to see how good it takes to run each one. And then you can output a CSV file. So in spread sheet software you can sort them to best to worse or whatever. And for my research, just goes to the long list of expressions. I thought it will be fun to look at merging threat ideas and [ inaudible ] and reg x live dot com. And that was like the best for debugging my script because there were like really strange and terrible expressions that broke my script and some of them still do. I do not try to validate whether it is a real validated expression. To be honest the script is a little bit buggy. But it workings pretty well. I'm not going to say like this expression universally take 1.5 second, well it doesn't in this machine but still giving you an idea. So examples of real stuff in the wild. This is most complete URL validator. If you don’t need the most complete URL valid don’t do that. If are you using a DFA that will take 150 Megs each shot you use that expression. This is not so bad. Im just throwing an example in for those not bad. This supposed to validate long Window file names. Uses a less than a meg of a memory. This is probably the worse time dates or DFA from regex but it supposed to match any valid human name like people’s name like Mr. Whatever you know. This expression takes more than 4 seconds each time you use it with an evil string. And now I get into some of the IDS rules this one is not so bad memory wise. This one is really bad time wise and the actual rule is merge threat [ inaudible ] remote code execution. For the evil string that my script generates. It takings 1.6 seconds to validate. But if you think about this. But if it takes longer to your IDS to validate this string then it takes for me to send the packet have you a problem. And by the way last year at defcon I did a presentation on various things. But one of them, this script called 8 ball that will attempt to trigger every single idea rule in an IDS. You feed it a IDS rule set. It deconstruct all the rules. Makes a packet for each rule and sends it to a target. So this ideas has reg X on it. So this 8 ball script I added a speedball option now you can tell it to do redof for all of these packets as well. It will not trigger all the ideas rules, it will actually take the idea as long as possible and fail to match too so you would not see alerts in theory. And just to show an example because I'm talking ability the benchmark. But if you want to see what a string would look like with this tool for a real expression that’s what it generates. Cool, that’s what the main reason of automating. The OAS page Like obviously that make sense but I don't think I would ever really look at this expression and thinking, this is a terrible expression, take a while to validate with some string I haven’t thought of. But when you automate it I still get something like this but it still takes a while. And then looking at it in DFA context this is where I like give examples the worse I can possible throw at it. 150 mg doesn’t sound that bad. I think that other one that was really bad. I just want to see, yeah that's really -- wow, that's funny when I try to be the worse I possibly can that's about as good as I can can do. This is me trying to do a simple bad expression by building a big stage table and I barely get 10 megabytes more. But this is the worst I can do. And then for time one men forget about it. To do really bad with that one, I start with this expression and this is the same expression I'm going to use every time so like this string with 40 As and a B that will take 2 days and I tested that it took me 2 days right. ————and in theory it is and it really like times 2. So 54 As will take like a lifetime. And 81 A’s [ inaudible ] based on 13 14 billiopn years. it will finish it is infinity it will finish. But that doesn’t gonna mean much if it takes that long. And I’m almost done, I’m going to show the demo really quick. But I thought this is fun. Looking at an expression like this, right here. I’m not really immediately looking what this is for. But this is my none dos engine and and my dos engine. this are the strings I made for it. And I think that’s kinda cool. Because I look at that expression, yeah Viagra This is from regex lib. [ inaudible ] probably for spam. That's cool too automation is funny. More recently I did not dig into this one. But you can use that too. [ inaudible ] you ca use regular expressions on that. Again I kind of so the funny thing is this NFA or DFA I had to use any tricks to see what that was and it turns out is definitely not an DFA. Because it is not deterministic time wise. But it doesn't seem to be pure NFA either because is not double ever A I had. It seems that it is a hybrid. But it definitely has some NFA elements based on the exponential increase in this string that I gave to it. So an actual test that I did was a 100 bite file that is checking for malware I did. So up here is the rule that I am using. I have a file with 99 A and a B. That took me 13 hours to see if that was malware. Based on that definition. So that's kind of bad. That's harder to attack because I don't know of anybody that will be using a definition like that. That's just me trying to do it badly and really allot of the definitions I have seen most people don't use expressions they just use string and hex matches and build complex logics condition section here. And you know, pixels didn't happen this is screen shot. So is me timing it. [ inaudible ] Rule file with that text file [ inaudible ]. This is the 13 hours 19 minutes. I'm showing the output of an expression that's similar. And shows A and the B and I see is a 100 bites down there and demo time. Is a good time for me to take a drink again because it is testing the time on this. So it does have timeouts. So its not going crazy to take like your lifetime. So by defaulting it timeouts like 30 seconds. You can expressions that timeout you can define the time out as longer if you want to you can explore that. So by default it times out so you don't go crazy. And you see I'm running tool against the text file [ inaudible ] I wanted to see CSV that text files is back here. I'm giving it nonexpression. Some familiar is bad one, some not, the Viagra one and the bad regex lib one and it has finish. I'm going to open it up. Is tab limited and I know that's kind of weird it is not comma delimited but it was easier because a lot of expression have tab in them. So have expression output in it as well annoying without using a really good module for csv. So these are your expressions. you can see how long it takings. This one is clearly the worse of those. 11 seconds. But you see the 4 and a half second one so that's the dos time but I also timed how good expressions so I can timed a bad expressions here. 1 to 8 1 to 8 thing the anchor. Normally it can take like a split second but it could up to 11. So that's interesting thing is not always bad. And I giver it delta like the difference between the good and a bad. And then I give the memory assuming is DFA and clearly this one is the worst down here that was the one that build state table dos. So that's all I'm good to know. Which ones are the worse for time or memory. But I'm still interesting to know what the good and evil strings are as well because it didn't tell us. So I gave an option for that dash dash strings it doesn't measure the time so you get instantly. So if I go up here. You should get the feedback right away. So A dot plus RGH, is like ARGH, for the dos string and then simple string is just ARG. Some of them aren’t that disable. The dot string is A that's not going to take time as simple sting is B. Is A because is negating the whole thing. A bad one with a DFA would be this but the dos for the simple string is more for the NFA. and you're Viagra there the one you saw on the deck here and then you get this string one right here from regex lib. So that's the demo pretty quick. And it is on my github and again if you want that address it’s the guy down here and is over. [ APPLAUSE ] >> Thank you.