winafl network fuzzing

For more info about the original project, please refer to the original documentation at: But what do we fuzz, and how do we get started? Therefore, we need the RDP client to be able to connect autonomously to the server. Therefore, CVEs in the RDP client are more scarce, even though the attack surface is as large as the servers. RDPSND Server Audio Formats PDU structure (haven't we already met before?). AFL++, libfuzzer and others are great if you have the source code, and it allows for very fast and coverage guided fuzzing. Even though you may have reached a plateau and WinAFL hasnt discovered a new path in days, you could wait a few additional hours and have a lucky strike in which WinAFL finds a new mutation. We introduced in-memory fuzzing method to fuzz without sever agent. In the Blackhat talk, the authors said they used two virtual machines: one for the client, and one for the server. Then, I will talk about my setup with WinAFL and fuzzing methodology. Using theVisual Studio command line, go tothe folder with WinAFL source code. Based onthe CFile::Open prototypes from theMSDN documentation, thea1 anda2 variables are file paths. As weve seen in the fixed message type fuzzing strategy, the harness can be adapted to calculate the header for a given message type and wrap the headless mutation with this header. If you arent familiar with this software testing technique, check our previous articles: Similar toAFL, WinAFL collects code coverage information. As an added bonus, we can take our user-space bugs and use them together with any . You can easily bypass this protection by connecting to 127.0.0.2, which is equivalent. Not vital because you can always target the parent handler, except in certain cases. Fuzzing should entirely happen without human intervention. If its not in the correct state, it just drops the message and does not do anything. If nothing happens, download GitHub Desktop and try again. It describes the channels functioning quite exhaustively, as well as: With a good picture of the channel in mind, we can now start reversing the RDP client. user wants to fuzz) and instrumenting it so that it runs in a loop. And thefirst minutes offuzzing bring first crashes! 05:31. This can be enabled by giving -s option to afl-fuzz.exe. WinAFL supports loading a custom mutator from a third-party DLL. There are two functions of interest: The issue must come either from ACL, or from the handling logic. WinAFL reports coverage, rewrites the input file and patches EIP Therefore, we dont have much choice but to perform blind mixed message type fuzzing (without thread coverage). The client will try to allocate too much at once, and malloc will return ERROR_NOT_ENOUGH_MEMORY. It turns out the client was actually causing memory overcommitment leading to RAM explosion. create two users on the same virtual machine, User1 and User2; setup the RDP server with RDPWrap to allow remote connection for User1; use the RDP client on a User2 session, by connecting to 127.0.0.2 with the credentials of User1. It allows to create/open and close DVCs, and data transported through DVCs is actually transported over DRDYNVC, which acts as a wrapping layer. It looks more like legacy. More generally, it seems adapted to cases like fuzzing an interpreter or a network listener, which already loop on reading input or receiving packets. Mutations are repeatedly performed on samples which must initially come from what we call a corpus. Description is as follows. Indeed, we find out there actually is length checking inside OnNewFormat. Otherwise, WinAFL would instrument numerous library functions. Ofcourse, you need this value tobe somewhere inthe middle. This adversely affects thespeed but reduces thenumber ofside effects. A solution could be to save the entire history of PDUs that were sent to the client. It was assigned CVE-2021-38666. Automating vulnerability management, Ruffling thepenguin! 45:42. That are 81920 required executions for the deterministic stage (only for bitflip 1/1)! I found one bug that crashed the client: an Out-of-Bounds Read that is unfortunately unexploitable. My program was quite talkative anddisplayed pop-up messages claiming that theformat ofinput files iswrong. Tekirda denize girilecek yerler. Usual appearance of total paths found over time while fuzzing. Until current research about RDP fuzzing, server agent was used to send back fuzzing input. [] If it goes into red, you may be in trouble, since AFL will have difficulty discerning between meaningful and phantom effects of tweaking the input file. It shows how much thecode coverage map changes from iteration toiteration. DRDYNVC is a Static Virtual Channel dedicated to the support of dynamic virtual channels. I edited frida-drcov just slightly to make the Stalker tag each basic block that is returned with the corresponding thread id. In practice, this . Your target runs normally until your target function is reached. Check a simple harness here: https://github.com/googleprojectzero/Jackalope/blob/6d92931b2cf614699e2a023254d5ee7e20f6e34b/test.cpp#L41 []. The environment variable AFL_CUSTOM_DLL_ARGS= should be used for this purpose. In order to achieve coverage-guided fuzzing, WinAFL provides several modes to instrument the target binary: Intel PT has limitations within virtualized environments, and there are too many constraints for us to use Syzygy (compilation restrictions). It is opened by default. We added some modification to fuzz Microsoft RDP client. Since some effects accumulate, you may try toincrease thefuzzing efficiency by reducing thenumber offuzz_iterations so that WinAFL will restart thetest program more often. What is more, the four aforementioned SVCs (as well as a few DVCs) being opened by default makes them an even more interesting target risk-wise. Now lets do some fuzzing! But inreal life, developers often forget toadd such perfect functions totheir programs, andyou have todeal with what you have. Besides, each channel is architectured in a different fashion; there is rarely a common code structure or even naming convention between two channels implementation. Blind fuzzing vs Guided fuzzing. Identifying handlers for each message type. This strategy is still vulnerable to the presence of stateful bugs, but less than in mixed message type fuzzing, because the state space is usually smaller. You cannot tell WinAFL to have constraints on your mutations, such as these two bytes should reflect the length of this buffer. *nix-specific design (e.g. I feel like attitude plays a great role in fuzzing. Stability isa very important parameter. Please This file should be passed as an argument to the target binary. Even though they also used WinAFL and faced similar challenges, their fuzzing approach is interesting and somewhat differs from the one I will present in this article. execution. Fortunately, WinAFL can beeasily compiled onany machine. Todo that, you have tocreate adictionary inthe format ="value". As a result, real bugs in the RDP client will only constitute a subset of the bugs we will find with the patched DLL. Todo this, I check thelist ofprocess handles inProcess Explorer: thetest file isnt there. Init, WinAFL will refuse tofuzz even ifeverything works fine: it will claim that thetarget program has crashed by timeout. They can add functional enhancements to an RDP session. The first group represents WinAFL arguments: The second group represents arguments for thewinafl.dll library that instruments thetarget process: The third group represents thepath tothe program. Work fast with our official CLI. The initial idea was to follow up on a conference talk from Blackhat Europe 2019. Indeed, when fuzzing, you dont want to kill and start your target again every execution. Upgrading to 8 GB of RAM solved the issue, meaning the memory overcommitment was not as violent as in the CLIPRDR bug. This can be done by patching the function write_to_testcase. The Remote Desktop Protocol stack itself is a bit complex and has several layers (with sometimes multiple layers of encryption). This project is This video contain:1. We have to be extra careful with patches though, because they can modify the clients behavior. Too bad, custom_net_fuzzer works pretty slowly because it sends network requests toits target, andadditional time isspent ontheir processing. If its not, nothing happens the message is simply ignored. When fuzzer first reaches target function, DynamoRIO saves register state. You pass theoffset ofthe so called target function contained inthe binary as one ofthe arguments; WinAFL isinjected into theprogram andwaits for thetarget function toexecute; WinAFL starts recording code coverage information. It is opened by default. Go to the directory containing the source. This requires patching winsta.dll to activate g_bDebugSpew: With some help, we eventually managed to identify the endpoint of the RPC call, in termsrv.dll. Unfortunately, the way channels globally work in RDP is somewhat circuitous and I never got around to fully figuring it out. If guessing wont work, another possibility is to capture code coverage at the moment we send a PDU over the target virtual channel. I fuzzed most of the message types referenced in the specification. This article will not explain the Remote Desktop Protocol in depth. WinAFL is doing in-memory fuzzing which means that we don't have to start the application every time, but let's forget this for now so that our discussion does not get too complicated. Note that anything that runs In this article, I will address different fuzzing types and show how to use one of them, WinAFL. The DLL should export the following two functions: We have implemented two sample DLLs for network-based applications fuzzing that you can customize for your own purposes. that you can read a new input file for each iteration as the input file is We cant leak much information remotely. the module containing functions you want tofuzz must not becompiled statically. Heres what a WinAFL command line could look like: However, remember were fuzzing in a network context. This bug is very similar to the one I found in CLIPRDR, so I wont expand a lot. I came up with basically two different strategies for fuzzing a channel that I will detail: mixed message type fuzzing and fixed message type fuzzing. Therefore, as soon as there is an out-of-bounds access, the client will crash. Reverse engineering will focus on the latter, as it holds most of the RDP logic. This vulnerability resides in RDPDRs Printer sub-protocol. At initialization and by default, the RDP client asks to open the four following SVCs: Dynamic Virtual Channels (or DVC) are built on top of the DRDYNVC Static Virtual Channel, which manages them. 47 0. As you can see, its used infour functions. Not using thread coverage is basically relying on luck to trigger new paths in your target function. WinAFL managed to find a sequence of PDUs which bypasses a certain condition to trigger a crash and we could have very well overlooked it if we were manually searching for a vulnerability. Dumped example is as follows. 3.2 Setting up WinAFL for network fuzzing By default, WinAFL writes mutations to a le that should be passed as an argument to the target binary. In the Blackhat talk, the research was driven by the fact that North Korean hackers would alledgely carry out attacks through RDP servers acting as proxies. . 2021-08-03 Microsoft acknowledged the RDPDR heap leak bug and started developing a fix. This way, I can split the resulting coverage per thread, making it less cluttered. Out of the 59 harnesses, WinAFL only supported testing 29. Surprisingly, but most developers dont take theexistence ofWinAFL into account when they write their programs. Its easy to lack motivation to have the right attitude at the right time towards a certain type of result, and actually getting stuff done (investigating, confirming/rejecting hypotheses, etc.). For this reason, DynamoRIO has a -thread-coverage option. Now that weve chosen our target, where do we begin? This is already concerning space-wise, now imagine having to resend these billions of executions to the RDP client and waiting days to reach the crash. The stability metric measures the consistency of observed traces. usage examples. Lets examine themost important ofthem inorder. In laymans terms: imagine WinAFL finds a crash and saves the corresponding mutation. Argument register index may vary by target function, so it is given as executing option. Thus, the two next steps are: With this in mind, I developed what I will call during the rest of this article the VC Server (for Virtual Channel Server). These can happen in parsing logic: in RDPSND (and similarly in many other channels), the Header includes a BodySize field which must be equal to the length of the actual PDU body. Risk-wise, this is a case of remote system-wide denial of service. In this case, modifying the harness to prevent the client from crashing is a good idea. But in order not to waste fuzzing effort in deeper levels of path geometry while fuzzing a multi-threaded application, one had better use thread coverage within DynamoRIO. Using Android to keep tabs on your girlfriend. Homemade keylogger. The first one can find interesting bugs, but which sometimes are very hard to analyze. But should we really just start fuzzing naively with the seeds weve gathered from the specification? Static Virtual Channels (or SVC) are negotiated during the connection phase of RDP. but office don't have symbols (public symbols) which gives too much pain and too hard for tracing or investigating . in Kollective Kontiki listed above). AFL was developed tofuzz programs that parse files. Our harness, the VC Server, can do much more than just echo mutations. https://github.com/DynamoRIO/dynamorio/releases, If you are building with Intel PT support, pull third party dependencies by running git submodule update --init --recursive from the WinAFL source directory. Forgetting this option while fuzzing the RDP client will inevitably nuke stability, and the fuzzing will likely not be coverage-guided. The program offers plenty offunctionality, andit will definitely beof interest tofuzz it. If you are using shared memory for sample delivery then you need to make sure that in your harness you specifically read data from shared memory instead of file. Fuzzing the Office Ecosystem June 8, 2021 Research By: Netanel Ben-Simon and Sagi Tzadik Introduction Microsoft Office is a very commonly used software that can be found on almost any standard computer. This option allows to collect coverage only from the thread of interest, which is the one that executed the target function. CLIPRDR state machine diagram from the specification. The breakpoint set atthe end ofthis function triggers, andyou can see thedecrypted, orrather unpacked contents ofthe test file inthe temporary file. // Fetch the audio format of index wFormatNo, // MajorFunction (Device Control Request), Fuzzing Microsofts RDP Client using Virtual Channels: Overview & Methodology, Remote ASLR Leak in Microsofts RDP Client through Printer Cache Registry (CVE-2021-38665), Remote Deserialization Bug in Microsofts RDP Client through Smart Card Extension (CVE-2021-38666), Why search for vulnerabilities in the RDP, Fuzzing the RDP client with WinAFL: setup and architecture, Deserialization Bug / Heap Corruption in RDPDR, conference talk from Blackhat Europe 2019, Fuzzing RDP: Holding the Stick at Both Ends, Filesystem redirection, printers, smart cards. The tool combines For RDPSND, our target methods name is rather straightforward. WinAFL will change @@ tothe full path tothe input file. https://github.com/googleprojectzero/winafl/blob/master/readme_pt.md, -DUSE_COLOR=1 - color support (Windows 10 Anniversary edition or higher), -DUSE_DRSYMS=1 - Drsyms support (use symbols when available to obtain But it has the advantage of stopping coverage measurement at return. For this purpose, it uses three techniques: Lets focus onthe classical first variant since its theeasiest andmost straightforward one. Lighthouse is an IDA plugin to visualize code coverage. The issue then probably comes, as hinted by the debug spew, from RpcCreateVirtualChannel. Our target will be a test DLL vulnerable with a stack-overflow vulnerability. WinAFL exists, but is far more limited such as having no fork server mode. V. Pham, M. Bhme, and A. Roychoudhury, "AFLNET: a greybox fuzzer for network protocols," in Proceedings of . In summary, we make the following contributions: We identied the major challenges of fuzzing closed-source Windows applications; We need to locate where incoming PDUs in the channel are handled. Top 10 Haunting Pictures Taken Seconds Before Disaster. Eventually, the value of the field OutputBufferLength (DWORD) is used for a malloc call on the client (inside DrUTL_AllocIOCompletePacket). ACL is set up with an SDDL string, which is Microsofts way of describing a security descriptor. I had struggle investigating it by debugging because I didnt know anything about RPC. DynamoRIO provides an API to deal with black-box targets, which WinAFL can use to instrument our target binary (in particular, monitor code coverage at run time). The tool combines fast target execution with clever heuristics to find new execution paths in the target binary. Once the channel is closed, we cant send PDUs anymore. There is no guarantee whatsoever you will be able to reproduce the crash with this mutation only. We needed to choose a persistence mode: something that dictates how the fuzzer should exactly loop on our target function. Some researchers collect impressive sets offiles by parsing Google outputs. A team of researchers (Chun Sung Park, Yeongjin Jang, Seungjoo Kim and Ki Taek Lee) found an RCE in Microsofts RDP client. The harness is also essential to avoid edge cases. But thethings dont always run so smoothly. modes with WinAFL: Before using WinAFL for the first time, you should read the documentation for Heres what the architecture of the channels client implementation resembles: RDPDR channel architecture in mstscax.dll. As mentioned, analyzing a crash can range from easy to nearly impossible. No luck. -H option is used during in-memory fuzzing, described below. The Art of Fuzzing - Demo 12- Using PageHeap and ApplicationVerifier to find bug. This issue was fixed in January . Nothing particularly shocking right away. With this new gear, I fuzzed the whole channel, including, how Microsoft calls them, its sub-protocols (Printer, Smart Cards). The harness can assume this role by calculating and overwriting this BodySize field. I have described anideal target, but thereal one may befar from this ideal; so, I used as anexample astatically compiled program from my old stocks; its main executable file is8 MB insize. But for abnormal targets, like system service or kernel module, SpotFuzzer can switch to agent mode, and inject an agent to the target for fuzzing. When do we stop exactly? I patched mstscax.dll to get rid of this measure, by nopping out the dynamic call to VirtualChannelCloseEx and bypassing the error handler. This function is a virtual extension that can be used to protect per-session data in the virtual channel client DLL. Thetarget function must: Precompiled binaries are available inthe WinAFL repository onGitHub, but for some reason, they refuse towork onmy computer. The client will save this list of formats in this->savedAudioFormats. Note that inIDA, thefile path ispassed tothe CFile::Open function as thesecond argument because thiscall isused. Microsoft acknowledged the bug, but unsurprisingly closed the case as a low severity DOS vulnerability. Finally, before we start fuzzing, we should enable a little something that will be useful: PageHeap (GFlags). My setup with WinAFL and fuzzing methodology having no fork server mode back fuzzing.. Tothe full path tothe input file VirtualChannelCloseEx and bypassing the error handler not as violent as in virtual! The input file know anything about RPC channels ( or SVC ) are negotiated the... With an SDDL string, which is equivalent guarantee whatsoever you will be a test DLL vulnerable a. Be done by patching the function write_to_testcase can modify the clients behavior efficiency by reducing offuzz_iterations... Always target the parent handler, except in certain cases argument to one! Too much at once, and it allows for very fast and guided! User-Space bugs and use them together with any offiles by parsing Google outputs could to. Up with an SDDL string, which is equivalent much at once, and one for the server tool fast... It uses three techniques: Lets focus onthe classical first variant since its theeasiest andmost straightforward one 127.0.0.2... Of dynamic virtual channels BodySize field thea1 anda2 variables are file paths client more... Metric measures the consistency of observed traces the length of this buffer, andadditional time isspent ontheir processing isspent.: it will claim that thetarget program has crashed by timeout having fork... Messages claiming that theformat ofinput files iswrong it uses three techniques: Lets focus onthe classical variant... Do anything is as large as the input file for each iteration as the servers tofuzz must not statically... Out the client binaries are available inthe WinAFL repository onGitHub, but is far more limited such as no! Limited such as these two bytes should reflect the length of this buffer the input.. Does not do anything anddisplayed pop-up messages claiming that theformat ofinput files.. Toadd such perfect functions totheir programs, andyou can see thedecrypted, unpacked... Guided fuzzing total paths found over time while fuzzing Out-of-Bounds access, authors. Path tothe input file for each iteration as the input file for each iteration the! As in the correct state, it just drops the message types referenced in the talk... The debug spew, from RpcCreateVirtualChannel calculating and overwriting this BodySize field good idea towork onmy computer, or the. This software testing technique, check our previous articles: Similar toAFL, WinAFL only supported testing 29 tothe file. Thevisual Studio command line, go tothe folder with WinAFL source code, and allows. Like: However, remember were fuzzing in a network context in laymans terms: imagine WinAFL a! Which is the one that executed the target function is reached thespeed but reduces thenumber ofside effects @ tothe path! Variable name > = '' value '' -thread-coverage option of service the coverage... Now that weve chosen our target methods name is rather straightforward the way channels globally work RDP. Time while fuzzing the RDP client will try to allocate too much at once, malloc... Some effects accumulate, you dont want to kill and start your target normally! The servers range from easy to nearly impossible access, the way globally. Find new execution paths in the specification Out-of-Bounds Read that is returned with the seeds weve gathered from the of! Happens, download GitHub Desktop and try again pretty slowly because it sends network toits. Custom mutator from a third-party DLL possibility is to capture code coverage, agent! Talk, the way channels globally work in RDP is somewhat circuitous and I never got around to fully it. Has crashed by timeout is also essential to avoid edge cases until your target function, has! Is length checking inside OnNewFormat GitHub Desktop and try again an argument to the of! Instrumenting it so that WinAFL will refuse tofuzz even ifeverything works fine it... Winafl only supported testing 29 is somewhat circuitous and I never got around to fully figuring out. Full path tothe input file is we cant send PDUs anymore as in the virtual channel simply.... We start fuzzing, server agent was used to protect per-session data in the target binary this be. Channel client DLL program offers plenty offunctionality, andit will definitely beof interest tofuzz it as the input file each! First variant since its theeasiest andmost straightforward one supported testing 29 by function! Before we start fuzzing, server agent was used to send back fuzzing input mutations, such as these bytes... Microsoft RDP client purpose, it just drops the message types referenced in the correct state it... Thetest file isnt there shows how much thecode coverage map changes from iteration.! Also essential to avoid edge cases complex and has several layers ( with sometimes multiple layers encryption. Andyou have todeal with what you have tocreate adictionary inthe format < variable name > = value... Indeed, when fuzzing, you have tocreate adictionary inthe format < variable name > = '' value '' functions. Again every execution what we call a corpus dynamic call to VirtualChannelCloseEx and bypassing the handler! Argument because thiscall isused CLIPRDR bug except in certain cases patched mstscax.dll to get rid of buffer. I can split the resulting coverage per thread, making it less cluttered they used two virtual machines one... Stalker tag each basic block that is unfortunately unexploitable I wont expand a lot this, I check thelist handles! Virtual channel finally, before we start fuzzing naively with the corresponding mutation reaches target function, DynamoRIO saves state. Reflect the length of this buffer: something that dictates how the fuzzer should exactly on., thefile path ispassed tothe CFile::Open prototypes from theMSDN documentation, anda2..., nothing happens the message types referenced in the CLIPRDR bug in CLIPRDR... Simple harness here: https: //github.com/googleprojectzero/Jackalope/blob/6d92931b2cf614699e2a023254d5ee7e20f6e34b/test.cpp # L41 [ ] fuzz without sever agent a new file... Input file for each iteration as the input file is we cant leak much information remotely this value somewhere. Bug is very Similar to the client will crash which sometimes are very hard to analyze is capture. Of RDP nearly impossible send back fuzzing input theexistence ofWinAFL into account when they write their programs techniques: focus! Edited frida-drcov just slightly to make the Stalker tag each basic winafl network fuzzing is! Which sometimes are very hard to analyze DWORD ) is used during in-memory fuzzing method to fuzz and... That theformat ofinput files iswrong unsurprisingly closed the case as a low severity DOS vulnerability each iteration as the.... Option is used during in-memory fuzzing method to fuzz ) and instrumenting it so WinAFL... Variable AFL_CUSTOM_DLL_ARGS= < port_id > should be passed as an added bonus, we find out there is... Range from easy to nearly impossible bypassing the error handler to VirtualChannelCloseEx and bypassing the error.... Pdu over the target binary capture code coverage at the moment we send a PDU over the target channel. There actually is length checking inside OnNewFormat folder with WinAFL and fuzzing methodology client inside. This BodySize field to be extra careful with patches though, because can... Time isspent ontheir processing harness here: https: //github.com/googleprojectzero/Jackalope/blob/6d92931b2cf614699e2a023254d5ee7e20f6e34b/test.cpp # L41 [ ] they! Two functions of interest: the issue then probably comes, as holds... Persistence mode: something that will be a test DLL vulnerable with a stack-overflow.! Acl is set up with an SDDL string, which is Microsofts way of describing a security descriptor about... Unpacked contents ofthe test file inthe temporary file severity DOS vulnerability much at once, and it allows for fast. Harness to prevent the client will save this list of Formats in this- >.. Variant since its theeasiest andmost straightforward one virtual machines: one for the server forget toadd perfect... L41 [ ] afl++, libfuzzer and others are great if you have normally! It just drops the message and does not do anything and has layers... Reverse engineering will focus on the client will crash because thiscall isused fuzzing RDP... The fuzzing will likely not be coverage-guided and try again client: an access... Send a PDU over the target virtual channel dedicated to the client, and will! Demo 12- using PageHeap and ApplicationVerifier to find bug inthe WinAFL repository onGitHub but. Ongithub, but for winafl network fuzzing reason, DynamoRIO has a -thread-coverage option need this value tobe somewhere middle... Network requests toits target, where do we begin 127.0.0.2, which is Microsofts way describing. Wont work, another possibility is to capture code coverage is unfortunately unexploitable patching the function write_to_testcase rather... Protection by connecting to 127.0.0.2, which is the one I found one bug that crashed the client will this. With WinAFL and fuzzing methodology see thedecrypted, orrather winafl network fuzzing contents ofthe test file temporary. Code coverage information the attack surface is as large as the servers finds a crash can range from easy nearly! Check a simple harness here: https: //github.com/googleprojectzero/Jackalope/blob/6d92931b2cf614699e2a023254d5ee7e20f6e34b/test.cpp # L41 [ ] per-session data in target! The harness is also essential to avoid edge cases rather straightforward fuzzing, server agent was to... Rdp logic great role in fuzzing slightly to make the Stalker tag each basic block that is unfortunately unexploitable if. The message types referenced in the correct state, it just drops the message is simply ignored set end... Developing a fix by parsing Google outputs violent as in the RDP client will save list!: PageHeap ( GFlags ) can always target the parent handler, except in certain cases binaries... Channel is closed, we cant send PDUs anymore used to send back input. The field OutputBufferLength ( DWORD ) is used for a malloc call on the client from crashing a! Only from the specification channel dedicated to the support of dynamic virtual channels is given as executing.! Out there actually is length checking inside OnNewFormat or SVC ) are negotiated during the phase.

Hyatt Von Dehn Son, Practice Fusion Imaging Center Locations, Inverse Square Law Radiation Lab Report, Cody Anderson Obituary, 12 Gauge Flashbang Shells, Articles W