Hi and welcome to our talk. My name is Guillaume Fournier. I'm a security engineer at DataLog and today, Sylvain and I are going to present the rootkits that we implemented using eBPF. If you don't know what eBPF is, don't worry. We are going to present this technology and tell you everything you need to know in order to understand the talk. So let's start with a few words about us. We are the cloud workload security team. We usually use eBPF for good and our goal is to detect threats at front-time. Everything we do is added to the DataLog agent, which is an open-source project, so feel free to check it out if you are interested. That being said, for DEF CON, we decided to use everything we knew about eBPF to build the ultimate rootkits. So as I said before, we are going to start the talk with a brief introduction to eBPF. Then Sylvain will take it over to talk about how we implemented obfuscation and persistent access in our rootkits. After that, I will come back to present the command and control feature along with some data exfiltration examples. And then I will talk about the network discovery and RAS bypass features of the rootkits. And finally, Sylvain will present a few detection and mitigation strategies that you can follow to detect rootkits such as ours. All right, so let's start with eBPF. eBPF stands for extended Berkeley packet filter. It is a set of technologies that can run sandbox programs in the Linux kernel without changing the kernel source code or having to load kernel modules. It was initially designed for network packet processing, but many new use cases were progressively added. So for example, we can now use eBPF to do kernel performance tracing along with network security and runtime security in general. So how does it work? So eBPF is simply a two-step process. First, you have to load your eBPF programs in the Linux kernel, and then you need to tell the kernel how to trigger your programs. So let's have a look at the first step. eBPF programs are reached in C. So it's not exactly C. It's more like a subset of C because of many restrictions that eBPF has to follow. But I'm going to talk about this later. So once you have your C program, you can use LLVM to generate eBPF bytecode, which you can then load into the kernel using the BPF C score. eBPF programs are really made of two different things, eBPF maps and the actual program. So there are a lot of different types of eBPF maps, but all you need to know is that they are the only way to persist data generated by your eBPF programs. Similarly, there are a lot of different program types, and each program type has its own use case. However, regardless of the program type, each program has to go through the same following two phases. So the first one is the verifier step. So I will talk about this later, but for now, just know that this ensures that your program is valid. And second, your eBPF bytecode will be converted into machine code by a just-in-time compiler. And when those two phases succeed, your program is ready to be executed. Step two is attaching eBPF programs. So in other words, this is when you tell the kernel how to trigger your program. So there are many different program types, and I can't present them all, but I'm just going to talk about four of them. So for example, you can use a K probe to trigger an eBPF program whenever a specific symbol in the kernel is called. Trace points are similar to query probes, but the hook points on which they can be attached have to be declared manually by the kernel developers. Those two programs require another syscall in order to be attached, and this syscall is the perf event open syscall. So the other two program types I wanted to talk about are TC classifiers, so it's SCAD-CLS, and XDP programs. So those program types can be used to do packet processing, so whenever some network traffic is detected at the host level or at a specific network interface level. Those two require a net click command to be attached. And the only thing to remember here is that each program type has its own setup, and thus map require a different level of access. Another very important fact about eBPF is that eBPF maps can be shared between different programs regardless of their program types. Alright, so the eBPF verifier, so the verifier is used to ensure that eBPF programs will finish and won't crash. To do so, it's really just a list of roles that the verifier checks, and your program has to comply with those roles. So for example, your program has to finish, it cannot be an infinite loop, so your program has to be a directed acyclic graph. You can have unreachable code, you can have unchecked differences, your stack size is limited, and your overall program size is also limited. And finally, one of the most infamous features of the verifier is its very cryptic outputs.  But yeah, basically you are in for a very painful debugging session. Last but not least, eBPF comes with a list of helpers that will help you access data or execute operations that you wouldn't be able to write natively. So for example, you have context helpers, you have map helpers, a lot of things that you wouldn't be able to write in C, and that you would need external instrumentation to do. In short, you have about 160 helpers, and most of the heavy lifting of your eBPF programs will be based on those helpers. So that concludes this introduction to eBPF, and I will hand it over to you Silvan, so that you can kick off the presentation of the break case. Thank you Guillaume. Before we get into the details, let's see why eBPF is an interesting technology to write a rootkit. First, the safety guarantee brought by eBPF means that a bug in our rootkit cannot crash the host. An error in the execution will not cause any log message to be emitted. The user therefore has no way to know that something actually went wrong, and notice the presence of the rootkit. As we saw earlier, the eBPF by code is converted to native code, and the number of instructions is limited, which limits by extension the performance impact that our rootkit can have on the machine that could otherwise be detected by the user. On the commercial side, eBPF is used by an increasing number of vendors, in various use cases, network monitoring, security for instance. With eBPF becoming widespread, the chance of one product being abused to load malicious programs also increases. The safety guarantee we just talked about should not give the security administrators the false feeling of security. There is a lot of activity around eBPF, and each new version of the Linux kernel comes with a new set of eBPF helpers, bringing new capabilities. As we wanted our rootkit to run on widely used distribution Linux such as Red Hat Enterprise Linux or the latest Ubuntu LTS, we used a limited number of helpers. Using recent helpers or features like KLSI would have probably made the development of the rootkit easier. One of the primary tasks of a rootkit is to hide itself. What does it mean in our case? eBPF programs are bound to a running process. If this process gets killed, all the attached eBPF programs will be unloaded. For that reason it is essential that we both hide our program and protect it from being killed. The eBPF programs and maps used by the rootkit should also be hidden, and we should forbid other programs to gain access to them through their file descriptors. So let's see our rootkit in action. So let's start the rootkit, which gives us its PIE. Then we can try your ps command in order to see if we can detect it from the output. We can try using its procfs entry and nothing. We can even try using a sub file or even a relative pass, and we still have the same issue, no such file directory. And finally we can try to send a signal to see what happened. And we get no such process error. The obfuscation capabilities of our rootkit mainly rely on the use of two eBPF helpers. The eBPF program right user helper allows our eBPF program to write into memory of the process that issues a syscall. This can be used for instance to alter the data that is returned by a syscall. It's also possible to alter the syscall arguments. There is one caveat with this helper. The memory to be modified has to be mapped into the kernel allyspace. Otherwise, a minor or a major page fault will be triggered, causing the bpf property user call to fail. The other bpf helper is to ease the bpf override return. This one allows you to change the return value of a syscall and has an interesting property. If this helper is used at the syscall exit, it will simply change the return value of the executed syscall. But if we use it at the entry of the syscall, the execution of the syscall will be completely skipped. It is important to note that this helper can only be used at the entry of the syscall or at the exit. So let's see how the obfuscation of a file actually works. At startup, the rootkit will populate a map with the pass of its pre-prog-pid folder. Now the user space issues a fragmented syscall such as state. This syscall usually comes in two forms. One that accepts the pass to the file as a string, another one that accepts the file you scripted for the file that the user space program must have previously retrieved using an open syscall. So let's consider the former. To properly identify the targeted file, the rootkit needs to do an accurate resolution of the pass as the pass-specific file could be a relative pass. At the entry of the syscall, there is not enough context to do the resolution. So we need to loop deeper in the kernel in our case in dbfs code. So we have the resolution, but at this point, we cannot block the syscall as we are outside of the allowed hookpoints for the ebpf override return helper. So the only thing that we can do is to change the return value so that the user space believes that the syscall failed. We also need to scrub the content of the structure that could have been filled by the kernel. Now let's consider the later, the version that accepts the file you scripted. We do the same pass resolution as before, but instead of just pretending to the user space that the syscall failed, we store the file descriptor that the kernel allocated into an ebpf map. If the same processes issues the syscall with the same file descriptor, we can, at the syscall entry, return an error and block the syscall. In this situation, the user has no way to know that the file descriptor exists. Anyway, as we control the read the syscall, we can also hide all the references to the file descriptor in procfs. Blocking the syscall that accepts the PID as an argument is trivial using bpfr return, same for loading kernel modules. Now let's see a demo, let's demo the obfuscation of our bpf programs and maps. So we still have the rootkit started, and if we list the maps and the programs, thanks to the bpf tool command line, we can't see anything related to the rootkit. Now if we start a binary loading some kprobs and maps, and we list again the programs, we can't see the programs related to the binary but still nothing related to the rootkit. Then we can even try checking the kprobs and still nothing related to the rootkit. The idea is to hook into the ebpf syscall itself. Two things are required here. We want to avoid the user space to iterate through the IDs of our entities using the bpf proget next ID command, and we need to prevent the user space from getting a file descriptor to the program or map from a DID using bpf proget fd by fd, basically to prevent ID guessing. Once these operations are endowed by the rootkit, the user space is not able to view or modify our programs and maps. bpf provide user is a crucial part of our rootkit, but it comes with a pitfall. When an ebpf program that makes use of it is loaded, the kernel prints a pretty scary but legitimate message in the kernel ring buffer. So let's see how the rootkit endowed this. First, let's check what is the current status of the kernel ring buffer using the command line dmissage. So nothing special here. And we can even start a cat on the device used by the ring buffer. Then we start the rootkit. So we can see that the cat terminated with a pretty legit looking message. We can recheck the kernel ring buffer thanks to the dmissage command line. We can only see legit looking messages, but a bit more. And then we can stop the rootkit and we can run again the dmissage command line in order to see what was overwritten by the rootkit. So let's see how it works. In this diagram, journal D is waiting for a new message and is blocked on a readc skull. Two bpf programs are loaded sequentially by the rootkit. The first one, which doesn't use the bpf provide user, will hook on a readc skull and will make it return 0 and will write a legit looking message. This will guarantee that the warning message is related to the bpf provide user won't be read. Then the second program using bpf provide user is loaded. At this point, the readc skull can be unblocked and we can override the content of the warning messages with legit looking messages. Another important task for the rootkit is to set up a persistent access across reboots for instance. The rootkit can copy itself to a dedicated place and hide its binary file with the same mechanism that we already saw. For the persistent access to the system, we can use a generic method close to what we described in the obfuscation part. We can replace the content of some critical files read by the root demands such as currently cronzy or even sshd. Let's see an example targeting sshd and using the read override approach. So the approach here is to happen an ssh key to the authorize key files. Only sshd should be impacted, meaning the file will remain the same for the user point of view. And we want to have it available through the command and controls. So let's see this in action. So let's check the authorize keys content first. So we can see that only one key is present. So let's start the connection and it seems that the password is required. So now we are going to start the rootkit and we are going to specify that we want to inject an ssh key to the authorize keys file but only for ssh. So we can try your connection again and it seems to be successful. And now we can check what is the content of the authorize key from the user point of view and nothing changed apparently. Persistent access to an application database can also be set up using an azalt type of evpf program. Uprobs evpf programs attach to user space permission. In addition to being safer and easier to use than ptrace, they offer a valuable advantage. The kernel will automatically set up for us the hooks on every instance of the program. Let's see a uprob demonstration using prosgres sql. So first let's try to connect to prosgres sql using the word bonsoir as password. This one seems to be the good one. Then trying hello and this one is rejected. Now we start the rootkit and we will get the opposite result. Now the valid password is hello. So the idea here is to hook on the md5 crypt verify function of the prosgres sql that check whether the user provided the right md5 for its forward passwords and the challenge sent by the server. Overwriting the expected hash contained in shadow pass with a known value makes the comparison succeed and gives persistent access to the database to the attacker. Now I will hand over to Guillaume that will show you the command and control capabilities of the rootkit. Thank you Sylvain. Let's talk about the command and control feature of the rootkit. So what exactly do we want to do? We want to be able to send commands to the rootkit to extract data and to get remote access to the invoket hosts. Unfortunately there are a few evpf-related challenges that we need to face in order to implement those features. First you can't initiate a connection with evpf. Second you can't open a port. However evpf can hijack an existing connection. So in order to show up this feature we have set up a very simple infrastructure on AWS. A web app was installed on any c2 instance and we used a classic load balancer to redirect HTTPS traffic to our instance over HTTP. In other words the TRS termination is done at the load balancer level and HTTPS requests are sent to our instance unencrypted. So our goal is to implement cnc by hijacking the network traffic to our web app. First we need to figure out which evpf program types we're going to use in order to implement this feature. Although evpf provides a lot of options to choose from we decided to go with two evpf program types xdp programs and tc classifier programs. So both those programs are usually used to do deep back gate inspection use cases and while xdp only works for ingress, tc works on both ingress and egress traffic. Another difference between the two program types is that xdp programs can be offloaded to the network interface controller which essentially means that your program will be run before the packet enters any subsystem into the network stack. On the other hand tc programs have to be attached to a network interface but like much later in the network stack which means that they are triggered later in the kernel. With both programs you can drop allow and modify your packets and with an xdp program you can also retransmit a packet. This option is actually super interesting for us because it means that you can you can essentially receive an answer to a packet even before it reaches the network stack which in other words means that you can do this even before it reaches any kind of network firewall or monitoring on the host. Skipping the network stack also explains why xdp programs are mainly used for DDoS mitigation and tc programs are usually used to monitor and secure network access at the pod or container level. So what you need to remember about this slide is that first xdp programs can be used to hide network traffic from the kernel entirely and tc programs can be used to extra trade data on its way out. Okay first let's see how we used xdp programs to receive commands with the rootkit. So we implemented a client for the rootkit and this client communicates with the rootkit by sending simple https requests and with a custom route in custom user agent. So after going through the load balancer the request eventually reaches the host and triggers our xdp programs. Then our program parsed the requests, the http routes and understand that this request is not meant for the web app but is meant for us. So after reading the user agent the rootkit executes the request that can end and moves on to the final step. So this final step is probably the most important one. It overrides the entire request with a simple health check request and we do this for two different reasons. First we don't want the malicious request to reach the web app or any kind of user space monitoring tool that might be running and that might detect the unusual traffic. And second we want the client to receive an answer in order to know if the request was successful. So as I said before we could also have dropped the the packet entirely but since we're using TCP the load balancer would have retransmitted the packet over and over again until the request times out. And this would have generated noise and increase our chances of getting discovered. That said if you have I mean if you were working with a UDP server this would be a totally valid strategy. So let's have a look at how we can send progress credentials remotely. All right so on the left of the screen you can see two different shells. Those shells are connected to the remote infected hosts on AWS and on the right this is my local shell and this is the attacker machine. Okay so let's start with trying to log into the progress database using the normal password and again the rootkit is not running yet. So as you can see the Bonsoir password works fine and then let's start the rootkit and restart to login again and as expected and as you've seen before during a Sylvain's demo it doesn't work so you have to change into hello and this time it will work. Here you go. Okay so we're going to try to do the same thing but instead of hard coding the new password with the rootkit we're going to define remotely through cnc what the new password should be. So as you can see we have a custom client that will make a request to HTTPS, an HTTPS request to defconn.demo.dog and then we will provide both the rule and the secret to override the normal secret with. So the request that we'll go through is a very simple one with a custom route and the user agent will contain the new password that will be used at runtime. So as expected we get the 200 okay from the health check which essentially means that we know that the new password now is defconn and not hello anymore. So as you can see hello doesn't work but if I change it to defconn here we go this time it will work. Okay so this is how we send a command to the rootkits. Now let's see how we can exfiltrate data. So to exfiltrate data the client has to send an initial request to specify what kind of data and what kind of resource we want to exfiltrate. So the xdp part of this process is basically the same as before but this time the xdp program stores the network flow that made the request along with the request resource the requested resource sorry in an ebpf map and the reason why we do so is because when the web app answers the health check we want to be able to detect the packets that are meant to be sent back to the client. So when the HTTP answers answer reaches the tcegress classifier our ebpf program looks up the network flow and overrides the answer with the requested data. Now the question is what kind of data can you exfiltrate with the rootkits right and the answer is well pretty much anything that is accessible to ebpf and the reason for that is as I said before multiple program types can share data through ebpf maps regardless of you know what those programs are supposed to do. So basically you can exfiltrate things like file content, environment variables, database dumps, in-marry data if you start looking at the stacks of the programs anyway you can pretty much exfiltrate whatever you want. So let's have a look at a simple demo that is we can exfiltrate postgres credentials along with the file content of edc password d. All right so and again the two shells on the left are the ones connected to the infected host in on the ws and on the right this is my local shell. So the first request that I make here is to list the I mean to do is progress list which basically means place list all the credentials that you have detected so far since the rootkit has started and as you can see the answer was sort of the hashtag answer was overridden with the content of a map that we used to store the passwords that we've collected at runtime and again remember that with progress you don't need the clear password to log in you just need the hash password that is stored in the database. Here you go so now we're going to try to do the same thing to dump the content of edc password d. So to do so this is a two-step process the first thing you want to do is tell the rootkit to start looking for this specific file and as soon as a user space process tries to open the file and read the content of the file our rootkit will actually copy the data as it is sent to the user space application and save it into the nubbf map so that it can be retrieved later. So this first request will tell the the the rootkit to start looking for edc password d and now let's go back to the host and you know do trigger some kind of sudo operation so that we can actually I mean so that a user space process tries to open the file. Here you go and then this time instead of saying add we're going to say get and this will dump the content of the edc password d file. Here you go. All right so the cool thing about this technique is that it applies to any unencrypted network protocol so for example we also implemented it for dns which means that you can actually use it to do dns poofing. So the only difference between the the normal way of doing this and and the dns poofing is that instead of using a tc program to override the answer of the request you will actually switch tc and xdp programs because dns requests are made from the host instead of received by the host. All right so let's move on to our network discovery feature. So I know everybody knows what it is but I have to say it anyway network discovery is the ability to discover machines and services on the network that so that you know where you want to go next in the infrastructure and also discovering services is a super important step when you are trying to pivot between hosts because it will tell you what kind of attacks you might want to try. So the word kit has two different network discovery features one of them is passive the other one is active and you can control both of them through command and control. So I'm going to get into more details later but basically the only difference between the two is the kind of network scanning you're looking for and also the level of traffic that you are willing to generate on the network. So first let's have a look at the passive option. So the passive option is simply a basic network monitoring tool so it will do pretty much the same thing as any other EVPF based network monitoring tool which means that it will listen for any ingress or egress traffic and then generate a graph from all the collected network flows. It will also show you the amount of data that was sent per network flow and to implement this feature we used our TC and XDP programs so the TC programs were used to monitor the egress traffic and the XDP programs were used to monitor the ingress traffic. So for this version of the word kit we are limited to IPv4 and TCP UDP packets that said support for IPv6 and other protocols could have been added easily. So the reason why the passive option is pretty cool is that it will not generate any traffic on the network in other words it is basically impossible to detect that someone is tapping into your network and more specifically the network that is you know that reaches this specific infected host. However this doesn't work for services that do not communicate with the infected host and so in other words the graph will definitely not be complete and that's also why we implemented the active method. So the active method is a simple ARP scanner along with a SYN scanner. So we implemented it using only our XDP programs which means that only I mean that the entire process is done without involving the kernel stack and although this will be a slower process you can use this method to discover hosts and services that are that are reachable by the infected host but that are not communicating usually with the infected host. And again the rootkit client will generate a nice network graph for you once the scan is complete. So on a technical level this feature of the rootkit is actually quite interesting because as I said before eBPF cannot create a connection from scratch so in other words we had to figure out a way to generate hundreds of SYN requests while dealing with this limitation of eBPF. So let's see how we solve this problem. So in order to send a SYN request you first need to know the MAC address of the IP that you want to scan. To do so we used the same trick that we've been using so far which is to override the request from the rootkit client. So when our XDP program receives a scan request for a specific IP in a specific port range it will override the entire request with an ARP request for the target IP. And then instead of returning XDP pass which is what we've done so far and also which would send the packets to the network stack our eBPF program returns XDP TX. So what XDP TX does is send the packet out to the network interface controller it came in from. In other words our HTTP packet was transformed into an ARP request and was sent back to broadcasted back to the entire local network. So eventually the target IP will answer the ARP request and we will be able to store the MAC address of this specific IP in any eBPF map. However during this entire process the TCP packet that was used to send the HTTP request was never acknowledged by the kernel and that is simply because it never made its way to the kernel in the first place which means that the load balancer or the client itself will eventually try to retransmit the packet and when this packet is retransmitted and when it eventually reaches our XDP program we will do the exact same thing but this time instead of because we know the MAC address instead of overriding the request with an ARP request we're going to override the request with a send request and more specifically a send request with the first port of the provided port range the target IP and the MAC address of the target IP. And assuming that the remote IP or the remote host doesn't have any kind of protection against send requests sorry, send scanning it will answer either resets or send plus act to this first request. So reset would mean that the port is open and send plus act would indicate that there might be a service running on the host. And this is where the basically the network loop happens and the reason why we were able to generate hundreds of packets without having to I mean while dealing with the limitation of EBPF that is the inability to create packets. So whenever we get an answer from a send request we override the received packet with another send request on the next port and we also switch the IPs, switch the MAC addresses and send it back again to the target IP and we do so in a loop until we go through the entire port range. So eventually the clients will try one last time to retransmit the initial HTTP requests because once again during the network loop we never answered the second retransmit. So eventually when this third retransmit reaches our XDP program we will override the request with the usual health check requests so that the 200 okay answer will make its way back to the client after the request was handled by the web app in user space. All right so let's see it in action. So on the right of the screen this is a shell to the infected host on the AWS and at the bottom here it's another one and at the top this is my local shell on my machine. So the first thing you want to do is to start the rootkit then second is to start damping the logs of the rootkit. So in EBPF you can actually generate logs using a trace pipe obviously you would not want to do this in a real use case for a rootkit but this is a great way of visualizing the scan as it goes through. Yeah so that's why I'm doing this and that's why you will see what the rootkit does at runtime. And then let's make the scan requests. So what I'm saying here is please scan the IP <IP_ADDRESS> from port 790 and for the next 20 ports after this one. So the first thing you can see is the request is immediately changed into an ARP request and we already got the answer for this ARP request. So next up when we get a retransmit we will change this into a scene request. There you go so the scene request went through and then you can see the loop that happened and we you know like increased port one by one until we reached the final port requested by the port branch. And then now we are waiting for the third retransmit and this retransmit will be the one that we override with the health check requests which means that we will eventually get here go the 200k and in other words you know the answer from the user space web app. All right so now what you want to do is retrieve the output of the scan and extract all the network flows that were detected at runtime. And here you go so you would say natural discovery get and eventually so it actually requires a lot of different requests because there is a lot of data to extract but eventually you will get the entire list of network flows that were captured by the work kit. Here you go so you have all the different individual flows and then more importantly you will have a graph generated for you so this one is the passive sorry active graph so as you can see in a range there you can see the arp request and replies from I mean between those different hosts and then in gray those are the scene requests and the reset answers and in red is the only scene plus act answer from the remote host. All right and then you have also the passive graph which is the one that we saw before. Okay so now let's move on to our rasp bypass. So rasp stands for runtime application self-protection. So in a few words a rasp is a new generation of security tools that uses runtime instrumentation to detect and block application-level attacks and more importantly it leverages its insight into the application in order to make more intelligent decisions. So simply put it is some kind of advanced input monitoring tool that can detect malicious parameters and can understand if a malicious input will successfully exploit a weakness from one of your apps. So the textbook example of a rasp is usually a SQL injection. So the rasp would implement multiple functions instruments sorry multiple functions in the libraries that you use and such as for example the HTTP server library or the SQL library and it will check at runtime that the user controlled parameters in your queries are properly sanitized. If not the rasp will stop the query before it reaches the database and redirect the client to an error page or some kind of error message. In other words a rasp relies on the assumption that the application runtime has not been compromised which is exactly what we can do with the BPF. So just a little disclaimer before I move forward. I want to stress the fact that we are playing outside of the boundaries of what a rasp can protect you from and more importantly this bypass does not apply to one specific rasp but to all of them because this is one of the core principles of how a rasp works. So let's have a look at how a rasp protects a go web app from a SQL injection. So let's say that you have a web app with a simple products page and a get parameter to specify the category of the products that you want to see. Chances are your web app uses the default go database SQL interface. So this is a generic interface that you can use to query your database without having to worry about the underlying driver and the database type that you're using. More importantly for us since it is such a generic interface this is usually where the rasp tools instrument your code because simply it's much easier to hook at this layer rather than having to hook onto all the underlying drivers. So when your request is handled by the web server the query will be formatted with the provided category parameter and eventually the web app will call the query context function of this SQL interface. This is when the rasp checks the the the query and makes sure that everything is normal and if it is the execution will resume its normal flow and the underlying query driver will be called. So in our example we use SQLite so the SQLite driver is called. Eventually the query makes its way to the database and the answer is sent back to the client. However if the rasp detects that's you know something is wrong or detects some kind of SQL injection it will block the query and redirect the client to an error page. Alright so now let's see what we did to bypass this protection. Well the answer is actually pretty simple. We added a Uprobe on both the database SQL interface and the SQLite driver interface. What this allows us to do is call one of our BPF programs right before the rasp checks the SQL query and trigger another one right before the the the SQL query is executed by the database itself. And thanks to the BPF pro bright user helper we can override the input parameters of the hooked functions so that the the rasp sees a benign query and the the database executes our SQL injection. And the cool thing about this is that we can even do it conditionally which means that we can bypass the rasp only if one specific SQLite password was added to the beginning of the query. Perfect so let's move on to the demo. As you can see we have a very simple web app so it's a shoes retailer so you have a lot of different products and you can filter by category. So let's try to do a simple injection using the get parameter. So the the injection will simply be union select star from user and because the rasp is not running right now the SQL injection should work here you go and if you scroll down this time you will see the users along with the passwords. Perfect so now let's restart the web app with the rasp which is what i've just done and try this again. So let's go to the shop and then override the category parameter. Perfect and this time the rasp blocked the request because it detected that you know someone tried to do a SQL injection and the SQL injection would actually have succeeded. Great so now let's start the root kit by providing the path to the web app and then try to refresh the page. So again this should also be blocked by the root kit by the the rasp because we haven't provided the the secret password for the bypass to work and the secret password is of course defcon and when we say defcon the entire process that I described before will be triggered and as you can see the rasp did not detect it. So that's all for our rasp bypass I hope you had fun just before I hand it over to Sylvain for the detection and mitigation strategies I wanted to say that unfortunately we won't have time to talk about the container breakouts that are implemented into the root kit however they have been presented during our black hat talk this year so if you are interested feel free to check it out that being said Sylvain take it away. So let's talk about detection and mitigation. How could we detect and protect ourselves from this type of root kit? We could do this at different levels. First if a vendor provided you ebpf programs you should go through an audit an an assessment phase of their programs some changes that that the code has to be gpl it probably uses some internal kernel symbols so you can ask for it. What should we be looking for? The program types that are used but also the ebpf helpers used the communication so maps between programs may indicate a potential risk in the case of that the vendor program is compromised. We developed a tool to assist in this auditing phase by inspecting the health files containing the ebpf programs it is able to list the used entities programs and maps and complete a graph of the interactions between them. The tool was run on our root kit with the following result we can identify on the graph that the xdp program has storing information into maps that are also used by some kprobs which correspond to the command and control capabilities of the root kits. It is also possible to mitigate at runtime the loading of such programs by monitoring calls to the bpfc's call and logging the usage of it. It will even be possible to protect the bpfc's call itself by either restricting the call to it to only some trusted processes or have the programs inspected before loading and rejected if they contain suspicious patterns or make use of some dangerous helpers. We could also compute and validate the signature of the programs before loading them. An initiative exists to add this verification logic to the kernel itself. Using tls everywhere for network traffic also helps mitigating the risk of a raw bpf program that intersect network data. Now if we were not able to block the loading of such a root kit how difficult would it be to detect its presence? Even if it's possible though very challenging to write an almost perfect bpf root kit we should concentrate on the action that the root kit would have to block and lie about the result of such actions. For instance our root kit disables the loading of the kernel modules because such a module would have the ability to list the bpf programs and the active kprobs. Now let's imagine that we insert a module that executes a specific action only known to us. The blocking of the module by the root kit would then be easy to detect. Monitoring the network traffic at the infrastructure level could help detecting hijacked connections or strange package returns mission. Our root kit being far from complete and far from perfect it should be relatively easy to detect it. That being said we hope it will bring to light the potential and the risk of such a new bpf based root kit while presenting some interesting technique. The code of both the root kit and the monitor is available at this addresses. Please have a look. Thanks for your attention and have a great conference.


We are now going to start with practical demonstration, and in this demo we will see a typical LPBOM application, an I2C master acquisition from a sensor triggered by a low power timer. In our example we are going to interface with ST's LSM6 DSO IMU. We will use the accelerometer part of this IMU. Low power timer 1 will be used as a trigger for the I2C transfer and also as a trigger to low power timer 3, which generates a PWM output on a GPO with a variable duty cycle. During the acquisition from the accelerometer, STM42U5 will be in stop-to mode with no software running, and it will wake up on a DMA transfer complete interrupt. As software tool prerequisites, we are going to use QMX 6.5.0 and STM42QU5 1.1.0. In addition, we will measure power consumption with STM42Q monitor power 1.1.1. This practical demonstration has been developed using NUCLEO-U575 connected via I2C to XNUCLEO-IKS-01A3. In this slide you have a reference of the connection needed as well as the reading and writing addresses for the accelerometer part of the IMU. In order to measure the power performance, we will interface NUCLEO-U575 with XNUCLEO LPM-A01 by the connection you can see in this slide. XNUCLEO LPM-01A will be connected via USB micro to our laptop to interface with STM42Q monitor power. We can now move to QMX in order to get started with peripheral configuration. Let's open QMX version 6.5.0. We click on access to MCU selector and we type STM42U575ZI T6Q. We select the power number and we click on start project. We won't use trath zone so we will not initialize it. We click OK, a new project we start to load. You can see the typical pinout view on the right and list of peripherals available on the left. While being on pinout view, we will select PC13 and we are going to assign user button to it. So we have to add a label here named user underscore button. After that, on PB7, we assign GPIO output functionality. And as label, we add blue underscore LED. We can now switch to the A to Z tab and we enable iCache one way. This trath zone cache tends to reduce the number of accesses to the memory, limiting the overall power consumption. As so previously, LPBAM makes use of DMA. So we are going to use LPDMA in link at least mode. We select channel zero and on channel zero setting, we have to make sure to have selected the generation of the transfer complete event at the end of the last link at least item. We also have to enable an interrupt from the NVIC settings. We can now have a look at power tab. We will talk more about this later on. As we wish to get the lowest possible power consumption, we will choose SMPS regulator, which is the switching mode power supply. On clock tab, we do not need to apply any change. We will keep the default configuration with 4MHz sysclock derived from MSIS. This is all for standard QBMAX configuration. We can now switch to LPBAM scenario and configuration tab, which is the biggest news coming from QBMAX 6.5.0. We are now on the LPBAM scenario tab. On the left, we have LPBAM management sector when I can add application. I click add application and once it is started, we can see two new tabs called scenario and Q. Qs, as we saw, are collection of functions which are linked by link at least based on LPBMA. A scenario is a collection of multiple Qs. Still on LPBAM management tab, we see on the left the settings sections. By checking these boxes, we will link the peripherals to the smartrun domain and LPBMA1. In addition, in LPBAM Functional Toolbox, we see a complete set of peripherals belonging to smartrun domain and related functionalities that can be used with LPBAM. These are all peripherals we saw previously in the slide. We have ADC, comparators, DAC, LP team, UR, SPY, OPAMP and VRF buff. We are now going to focus our attention on I2C3, which is the one we will use to interface with our IMU. In order to implement our scenario, we will use two Qs, made up of five and three functions respectively. Here we have the first Q implementing I2C transfer. This is using LPBMA channel zero. First function will be used to enable accelerometer and second and first, I use it to get six bytes of data from the accelerometer. Functions four and five are used to read six more bytes from the accelerometer. In total, we will acquire 12 bytes containing ASC by Z data.  Content of DTX buffer to enable the accelerometer and RX buffer to retrieve data are reported in this slide. Additional detail register map and command set of LSM6DSO can be found in application note number 5192 on ST.com. We now focus on the tab in the middle called Q1. On the right, we can find configuration for the whole Q. By means of this configuration, we define the behavioral variable function group that we will add. QBMAX abstracts the complexity in a super easy and efficient way, as you can see. As first parameter, for example, we can define the Q circularity that we will use later on. A second parameter priority, and in addition, QBMAX gives us the chance to enable various interrupts for an or handling overrun or transfer complete. In this case, we will select transfer complete interrupt. We will enable it as preemption priority will select the default and we stick with no privilege. It's now time to add functions in the queue. As we remember from the slide, we have five functions to be added. We can select them from the tab on the left. Click on I2C3 and first and second functions were master and transmit data. The first function was master receive data. The fourth was master transmit data. And the fifth was master receive data. Once done, we can click on first function, which contains the two bytes needed by our IMU to be initialized. It's a master transmit. Therefore, we need to add the device writing address. In our case, for the IMU we are using, it will be 0xd6. We are going to give our data buffer name ATXBuffer and as an offset, we are going to add 0. We will be sending two bytes, so number of data will be equal to 2. And we condition this first transfer to the rising edge of low power timer 1, channel 1. We have now completed the configuration of the first node. You have experienced that also in this case the easiness provided by QBMX in configuring the peripherals and the data packet to be sent. On the same logic, we will configure master and transmit function number 2. All the difference is that buffer name and number of data will be BTXBuffer and 1 respectively. The device address will still be the same 0xd6. Now we have to remember that we need to condition the I2C transfer on rising edge of the low power timer 1, channel 1. Now we can switch to function number 3, which is the master receive data. This is a reading, so we have to put the reading address of the sensor, which is 0xd7. We will assign our receiving buffer a name. As offset, we are going to add 0. We will explain this parameter later on. Number of data will be 6. We want also this function to be conditioned by a trigger, which is low power timer 1, channel 1. Now we have created and configured our first three functions. Function number 4 will be identical to function 2 and function number 5 will be equal to function 3. The only difference is that on data buffer offset, we will add 6, as we would like to have the whole 12 bytes written inside buffer temp to avoid overwriting. We are now going to configure very quickly these two additional functions. Now we can move to the Pinout and Configuration tab. First thing to notice in Pinout and Configuration tab is that it looks very similar to the well-known equivalent tab in Cubemax. All the difference is that we only have peripherals listed that can be active in Smartron domain while being in stop 2. We will see that Cubemax generates all initialization code needed to start LP1 scenario easily adding a few lines of code. If we want to be sure about peripherals to be configured, we can click on Check LP1 Design button. In this case, we are getting a warning, mentioning that I2C3 is used in Cubemax but not configured. This is another example of error-checking integration into Cubemax. As a first thing, let's configure I2C3. Very easily, we just need to enable it and we are fine with the default settings as GPIOs are aligned with our Outro settings. LP Team 1 should also be configured. We select as Mode Count Internet Clock Events. Reactivate Channel 1. We define the Compare Mode. And we are going to put Period and Pulse Value in order to have a trigger every 200 milliseconds. We now switch to an important tab called Power. Here we can define all the steps to enable power saving once LP1 scenario is activated. It's a new feature introduced in Cubemax specifically for ultra-low power performance of STM32U5. We are going to enable power down for all SRAM and related pages. Only exception will be SRAM for an iCache as we need to have nav available in stop 2 for running our application and getting low power performance. Once done, we can switch to ClockTab. Coming to ClockTab, we see it's very easy to understand as we already have grayed out all the selection of oscillator which are not available in LP1 mode. We can just select the wake-up clock between MSI and HSI and we have to select the clock for the peripherals we enabled. For I2C3, we select MSIK and for LP Team 1, we select LSI. Configuration is over. Now let's come back to Cubemax to generate code. From Project Manager, we can give our project a name and then we can select QBidE as preferred toolchain. On Code Generator, we flag the option Settle Free Pins as Analog. Then we can click on Generate Code. Now we can click Open Project and start to work on the firmware on QBidE.


This module presentation presents the key differences between the STM32 L4RXX 5XX and the STM32 L476 L486 devices. The STM32 L4 Plus series stretches the STM32 L4 technology by offering higher performance, that is to say 120 MHz 405 core mark executing from internal flash memory. The new STM32 L4 Plus embeds up to 2 megabytes of dual bank flash memory and 640 kilobytes of embedded SRAM. It also embeds advanced graphic features enabling state-of-the-art graphic user interfaces. The Chromart Accelerator, the ST proprietary 2D hardware graphic accelerator, efficiently handles repetitive graphic operations, releasing the main CPU capabilities for real-time processing or even more advanced graphic operations. The Chrom GRC round-display memory optimizer allowing up to 20% of graphic resources optimization. The LCD TFT controller and MIPI DSi controller supporting two lanes and two times OctoSPI supporting flash and SRAM memory. The system frequency is increased up to 120 MHz while keeping state-of-the-art ultra-low-power figures. The new STM32 L4 Plus series is fully pin-to-pin compatible with the STM32 L4 series except for the STM32 L4R9 and STM32 L4S9 lines. The two figures illustrate the LQFP 144 and LQFP 100 pin-out differences between STM32 L476 486 and the STM32 L4R9 and STM32 L4S9 lines. Let's have a look at the system architecture changes that we see with the STM32 L476 486 microcontrollers. The STM32 L4RXX 4SXX main system architecture consists of a 32-bit multilayer AHB bus matrix that interconnects nine masters and eight slaves. The main differences with STM32 L476 486 devices are highlighted with pink squares. The STM32 L4 Plus brings some new features in clock configuration management. The STM32 L4 Plus series features additional clock configuration. The main differences with the STM32 L476 486 devices are highlighted with pink squares. This table highlights the differences related to RCC mainly for PLL dividers and factors between STM32 L4RXXX and 4SXXX and STM32 L476XX 486XX microcontrollers. In STM32 L4RXX 4SXX devices, it is recommended to use a transition state while switching from low to high speed or from high to low speed system clock. This slide presents the recommended sequence for the transition state. These slides show the embedded SRAM memory mapping differences between STM32 L4RXXX 4SXX and STM32 L476XX 486XX microcontrollers and the interrupt vectors table as well. The STM32 L4RXX SXX devices feature an additional SRAM 3 of 384 kilobytes. Compared to STM32 L476XX 486XX devices, the SRAM 2 is contiguous to the SRAM 1 and it is still mapped at the 0X100000 address. This slide presents the external memory mapping differences between STM32 L4RXXX 4SXX and STM32 L476XX 486XX microcontrollers. This slide presents the interrupt vector differences between STM32 L4RXXX 4SXX and STM32 L476XX 486XX microcontrollers. We will now go through the key new aspects of flash memory between STM32 L4RXX SXX devices versus STM32 L47X 48X devices. The flash memory can be configured by option byte or D bank in single bank mode with 128-bit read access or in dual bank mode with 64-bit access. This slide presents the flash memory organization in single bank and in dual bank mode. In dual bank mode, the main memory is divided into two banks of one megabyte and each bank is organized by 256 pages of 4 kilobytes. In single bank mode, the main memory bank of 2 megabytes is organized by 256 pages of 8 kilobytes. This slide presents the option bytes differences between STM32 L4RXX SXX devices versus STM32 L47X 48X devices. In order to read the flash memory, it is necessary to configure the number of weight states to be inserted in a read access depending on the clock frequency. The number of weight states also depends on the voltage scaling range. The two tables present the differences in weight states between STM32 L4RXX SXX devices and STM32 L47X 48X devices. More features are also added into the STM32 L4 Plus microcontroller which gives the user more flexibility. The STM32 L4R9 and STM32 L4S9 devices feature the DSi or display serial interface subsystem and it uses several power supply pins which are independent from the other supply pins VDD-DSi, VCAP-DSi and VDD-12-DI. If a DSi peripheral is not used, the VDD-DSi must be connected to VDD while VCAP-DSi and VDD-12-DI can be left floating. The main regulator output voltage can be programmed by software in two power ranges, Range 1 and Range 2. In Range 1, the main regulator operates in two modes that can be selected by software. Range 1 Normal Mode provides a typical output voltage at 1.2 volts allowing a system clock up to 80 MHz. Range 1 Boost Mode provides a typical output voltage at 1.28 volts allowing a system clock up to 120 MHz. The Range 1 Normal Mode optimizes the power consumption up to 10% comparing to Range 1 Boost Mode. When you are using the USB or DSi peripheral, the Range 1 Boost Mode must be selected. The STM32 L4 Plus series features the same low power mode as the STM32 L4 series with an additional option to switch off or on the SRAM3 during stop 2 mode. The table you will see next details the changes between the series concerning communications and peripherals. This table summarizes the key differences for system peripherals between STM32 L4 Plus and STM32 L4 series. This slide continues the presentation of a summary of the key differences between STM32 L4 Plus and STM32 L4 series. Again, the differences are highlighted in pink. And here are some more peripheral updates between the two series. As already said in the introduction, STM32 L4 Plus embeds advanced graphic features enabling state-of-the-art graphic user interfaces. And finally, even though we have upgraded many key features of the STM32 L4, the working environment remains the same. So the STM32 L4 and STM32 L4 Plus product family share the same ecosystem software package known as the STM32 Cube. The STM32 Cube HAL is a common library which addresses the entire STM32 microcontroller family. Specifically, the STM32 L4 firmware package offers a standard HAL as well as low-layered drivers and examples. So, if you are already using our STM32 L4 Cube, you just need to upgrade it from www.st.com to get the latest version. For more details, please refer to application note AN5017 about migration from STM32 L476XX486XX to STM32 L4 Plus series microcontrollers.


Domingo Acevedo came close to making his Major League debut in 2018. Being promoted from the Miners in late July to serves an extra arm in the bullpen for a day in case a long reliever was needed. He did not get into the game and wound up being sent back down, so the 24-year-old right-hander still has yet to pitch in the Majors. Although that opportunity is probably not far off. He's fared very well throughout his time on the farm, including 14 games last season at AA Trenton, where he posted a 292 ERA in 14 appearances. He missed about a month and a half early in 2018 due to blister problems, and he set out the first few weeks of August because of upper arm soreness. But if health is on his side in 2019, the 6-foot-7, 250-pound Acevedo should be able to position himself for a possible call-up. He was the Yankees' minor league pitcher of the year just two seasons ago, so it makes sense to think we could see Acevedo in the Bigs sometime soon.


Good morning! Have a good morning! Merry Merry! So the question of the week is, what genealogy gifts are on your wish list? The profiles of the week are about Napoleon. And what's happening around WikiTree in December 2023?


It's The Cube. Here is your host, Jeff Crick. Hi, Jeff Crick here. We are on the ground at SAP Silicon Valley Campus in Palo Alto, California. And we're out for a really special event tonight. I've got to look. It's the Makers, Women Who Make America, Women in Business, which is a series put out by Makers, a documentary series, they're showing it on KQED, and as part of that program, they came here to SAP to promote the series, promote diversity, promote women in business, and we're joined here by our SAP host, Jenny Dearborn, SVP and Chief Learning Officer. Welcome. Thank you. Glad to be here. So, great event. You had probably 200 people that were out for the panel. We watched the movie together, and then we had a panel with four or five people, so we'd be happy to take a few minutes, get with the panel, and really dig in a little bit deeper. Great. So, first off, what is a Chief Learning Officer? We do 1,000 executives last year. All right. I don't know that we had a Chief Learning Officer. Chief Learning Officer means I'm responsible for all internal employee training, development, enablement, talent development, all the internal education that helps employees sort of be ready for the future, for the jobs of the future. That world is changing quite a bit, right, because now nobody wants to read anything that don't want to take a class, right, it's just supposed to be automatic, so your world must be changing. Yeah, it's very dynamic. There's a lot of mobile and social learning and all new ways of training and educating employees. That's right. SAP, the big announcement the other day, so exciting time. I know. It's a great time to be at SAP. So, let's dig into some of your comments, I think, that really jumped out of me. The first one was you talked about work-life integration, really, and I think the context was people talking about work-life balance, and you said there is no work-life balance, and I totally agree with you. Yeah, so work-life balance is sort of a crock. I mean, it's just not possible. What you can do is integrate all the pieces of your life and try to be sane at the end of the day and get everything done. So, you know, for me personally, I get up early, I do conference calls and emails in the morning. I always block off 7 to 8 a.m. That's wholly and sacred to get my kids up and out the door. I come into the office, I do work here, I go home, so when my kids come home from school, put dinner on the table, and then I'm back online, you know, everything just needs to be integrated.  But if you think that you're going to have balance and feel good about every little thing that you're doing, that's just not possible. And what about just kind of the continuing encroachment? I mean, can we get it all done or do we just have to do a better job of prioritizing? It's prioritization, it's outsourcing, it's knowing what to let go and just say, I don't need to have a perfectly clean house.  You know, I don't have to have everything spotless and organized in my life. I need to focus on what's truly important, what truly matters, and kind of let the lot of the little stuff go. I think that's a great concept. There's a lot of little stuff that people don't let go, that they can't let go and focus on the big stuff. Clean up some room for the big stuff. Yeah, exactly.  But what I thought that you talked about was unique is when it's the big jumps, right? It's one thing when you're getting started and you've got to kind of fit in and if everybody's having a drink, you probably got to have a drink and all these kind of things that when you're getting started working your way up. But you talked about the big jumps and those come every now and then. What's the magic to the big jumps? What opportunities? Who gave you those opportunities to make those big jumps? So I think it's really being prepared for those opportunities when they come. So it's working really hard all the time and never thinking, I have to push and push myself out there. You're always focused and working really hard and then be prepared for when somebody's going to come and tap you on the shoulder. And that's happened to me. I've been lucky enough that's happened a couple times in my career where I had a mentor that came to me and said, you're ready for this really big job. I said, I'm scared to death. I can't do that. But it's going to be good for you. It'll push you. You have to take this. And so then I went and applied for that job and then I ended up getting that job. So no one handed me a job but they pushed me into going and applying and that was great. And a lot of times the big jumps financially comes when you move companies too. You stay with the company for a while and you'll get a 3%, 5%. But those big double digit salary, advances sometimes come when you leave companies. And so you have to be comfortable sort of getting yourself out of your comfort zone and making a big switch in order to get those big financial jumps too. And that was another thing you talked about is that if you're in a place and it's just not working, you just got to go. Just go. I mean, if you are working really hard and doing amazing work and you're not getting recognized and you don't get the sponsorship and you don't get the mentorship and you've tried for a couple promotions or laterals or something and it's not happening for you. Why are you staying? I mean, you're torturing yourself, right? Go someplace where you can find your bliss where people will honor you and recognize your talent.  You had another interesting concept. You said, you tell people, imagine people are always watching you, which I find interesting. I do a lot of youth coaching and I try to tell that to the kids that even if the drill is not happening at practice, imagine the coaches are watching you. They're watching how you move. They're watching how you perform. They're watching how you, what your attitude is and you got to always be ready because you just don't know who's looking around the corner. You know when the ball's coming, right? Exactly. That's great. Exactly. So as a senior female executive, it's rare. We are rare. I mean, we'll admit it. Rachel said that tonight that in Silicon Valley, female executives are rare and so when you do come into the office and I travel about 50% of the time but when I am here, I know that people are watching me and so I need to make sure that I am always ready to go and have any conversation as someone approaches me in the hallway and they want to grab me for five minutes or things like that.  You never know when the coaches are watching you or the employees in the corporate cafeteria.  So last question, we're getting the hook an event like this. Why is SAP doing this? What does this tell you about the culture? Is this relatively new? Give us a little bit of background as why you guys set aside food, catering, 200 people. A really nice event. That's not an SAP event. It's not an SAP event. We're very honored to host it on behalf of KQED. SAP is an innovation company and so this is very much in the heart and soul of what SAP is and in order to innovate you need to have diversity and in order for diversity you need to encourage events like this. Women, if they don't see a woman in an executive level role they don't think that they can do it themselves. So you have to put your role models out there and make them very visible for others to see as they're coming up in the ranks and diversity makes us better. It makes better products. It makes us better customer-focused organization and diversity and innovation go hand in hand and innovation is what SAP is about. Excellent. Well Jenny, thanks for stopping by. Thanks for spending a few extra minutes. We've been here for a couple hours. Great event and we're really happy to take part in it. So you're watching theCUBE. I'm Jeff Frick. We're on the ground in Palo Alto at SAP Silicon Valley headquarters. Thanks for watching.


The presidential candidate of the Labour Party, Pital B, has said that his desire is to see that the nation's population becomes an asset and component of production. Obie stated this in Mkhag Wukong Local Government Area of Benway State, where he attended the NKST Synod. The presidential candidate said when compared to other nations like India and China, Nigeria's population was very low but stated that what should be done as a responsible government was to convert it to an asset. Hello, hope you enjoyed the news. Please do subscribe to our YouTube channel and don't forget to hit the notification button so you get notified about fresh news updates.


There are certain types of expression that simply can't exist in a static state. It's the difference between an inclination and a dream, the difference between polite applause and a standing ovation. At the University of Alabama, it is a dream that all students in the performing arts have the opportunity to reach their full potential in an environment without limitations. Soon the curtain will rise on the next act of performing arts at a program already known for graduating talented professionals ready to take their place on the national and international stage. The University is writing a new script and reimagining the role of Bryce Maine. A 21st century Renaissance will re-energize this historic facility and connect it to a world-class performance venue. The powerful combination of exceptionally talented students and faculty in the historic and pastoral setting of the Bryce property ensures that the Performing Arts Academic Center will be a marquee public space for the campus community as well as visitors. It's truly a unique situation that we get to be on stage, we get to take class and we get to teach classes, which means that it becomes a true laboratory for development. It is the East and Juliet is the sun. I would not have received the scholarship funds that I received through the Miss America Organization, through the Miss Alabama Pageant and through other opportunities had it not been for this program and had it not been for the quality of the faculty and staff in this program. The diversity in which graduates go on to achieve success speaks to the totality of what they prepare us to do and the discipline that they provide. As an instructor one of the limitations of the current facility is just the number of performance classrooms that we have. So what that means is that we have to limit our rehearsal periods as well. So we don't have the opportunity to go into breakout sessions so we can never fully delve into character. We can't be rehearsing multiple shows concurrently because of our limited space. It's the missing link to a complete overhaul of artistic education and advancement not only at the university but also for the state. We are the flagship in so many ways and it's now time that our performing arts environment and facilities represent that. And as an alum and a current student that's a very, very powerful thing to say that we'll finally catch up with the quality of our dancers and faculty. Mary and I have always loved the performing arts. Here at the University of Alabama we're blessed to have some of the greatest faculty in their field training the most talented students as they pursue their dreams. Having the opportunity to witness these brilliant young performers chase after their dreams is the very reason why we wanted a front row seat in this campaign. When we heard about the plan for the Performing Arts Academic Center we were delighted the university was making this commitment and we wanted to make a contribution. When we fully understood the plan for the Adjoining University Welcome Center in Bryce, Maine we saw this as a transformational facility. When it's completed the Performing Arts Academic Center will have a tremendous impact for our students, faculty, as well as for our entire community. Elevating these performances at every level this facility will enhance the educational experience with space dedicated to hands-on learning. We hope you will join us in setting the stage for greatness by first taking the time to understand the magnitude of this project and then by making a contribution to the campaign for the Performing Arts. To make this facility a reality we will need the financial support of our Alabama friends and those who love the Performing Arts and the University of Alabama as much as we do. Our students and faculty already boast a truly remarkable list of accomplishments and awards. With the support of our alumni and friends now it's time we give them a stage worthy of their ambition. The stage is set for greatness with a script in hand to allow UA students to excel, to inspire the patrons of Performing Arts and to expand the cultural offerings in the region. With your generous gift the curtain will rise on the performance of a lifetime.